01 / build & ship
Development
Comandos de trabajo diario para código, datos y contenedores.
Development Cheatsheet
Common commands for Rust, Node/pnpm, Python, databases, Docker and Git.
Git, SSH and Repository Access
SSH keys (ed25519 is the current default; use one key per machine):
ssh-keygen -t ed25519 -C "you@example.com" # generate a key (~/.ssh/id_ed25519)
cat ~/.ssh/id_ed25519.pub # copy this into GitHub/GitLab > SSH keys
ssh-add ~/.ssh/id_ed25519 # load it into the agent
ssh-add -l # list loaded keys
Verify the host key and that authentication actually works:
ssh -T git@github.com # "Hi <user>! You've successfully authenticated"
ssh -T git@gitlab.com # "Welcome to GitLab, @<user>!"
ssh -T -p 443 git@ssh.github.com # GitHub over port 443 (when 22 is blocked)
ssh -vT git@github.com # verbose, to debug which key is offered
Check that a repository is reachable, and whether you have push rights, without changing anything:
git ls-remote origin # server-side refs: proves fetch+auth and the URL
git ls-remote --heads origin # branches only
git ls-remote git@github.com:user/repo.git # check a URL before adding it
git fetch --dry-run # fetch without updating local refs
git push --dry-run origin main # talks to the server: fails if you lack push access
Remotes and identity:
git remote -v # current fetch/push URLs
git remote show origin # branches, tracking, push permissions
git remote set-url origin git@github.com:user/repo.git # switch HTTPS <-> SSH
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global credential.helper manager # cache HTTPS credentials (Windows)
CLI auth for the hosting platforms:
gh auth login # GitHub CLI (HTTPS or SSH)
gh auth status # which account/token is active
gh repo view user/repo # confirms read access
glab auth login # GitLab CLI
glab auth status
HTTPS needs a token (GitHub: fine-grained PAT with contents:write; GitLab: PAT with write_repository); SSH needs your public key registered. Both git ls-remote (read) and git push --dry-run (write) returning success is the full access check.
Common failure: Permission denied (publickey) means the key is missing or not registered; Repository not found over HTTPS usually means the token lacks scope or the URL/user is wrong.
Normalize text files to LF so Windows checkouts stop rewriting them. Add to .gitattributes:
* text=auto eol=lf
git config core.autocrlf false
git config core.safecrlf false
git add --renormalize . # stage existing files with the new line endings
git status
git add .gitattributes
git commit -m "chore: standardize line endings"
Git LFS for large binary files:
sudo apt-get install git-lfs
git lfs install
git lfs pull # download images stored in LFS
git lfs ls-files # list tracked files
Rust (cargo)
Day-to-day basics for a Rust/Axum backend and working with crates.
cargo build # compile in debug
cargo build --release # compile optimized
cargo run # compile and run
cargo run --release -- arg1 # pass arguments to the binary after --
cargo check # type-check without producing a binary (fast)
cargo test # run all tests
cargo test name -- --nocapture # a single test, showing println!
cargo clippy # linter
cargo clippy -- -D warnings # fail on warnings (useful in CI)
cargo fmt # format code
cargo fmt --check # only verify formatting (CI)
Dependencies and maintenance:
cargo add axum tokio -F tokio/full # add a dependency (with features)
cargo remove name # remove a dependency
cargo update # update Cargo.lock
cargo tree # dependency tree
cargo tree -d # duplicates only
cargo clean # delete target/
cargo doc --open # build and open documentation
cargo install cargo-watch # install tools
cargo watch -x run # rebuild and restart on save
cargo audit # known vulnerabilities (needs cargo-audit)
cargo expand # expanded macros (needs cargo-expand)
Publishing to crates.io:
cargo login # crates.io token (once)
cargo package --list # which files will be included
cargo publish --dry-run # simulate publishing
cargo publish # publish (irreversible; versions can only be yanked)
cargo yank --version 0.1.1 # stop new projects from depending on a version
With SQLx (for PostgreSQL):
cargo install sqlx-cli
sqlx migrate add name # create a migration
sqlx migrate run # apply it
cargo sqlx prepare # generate cache for offline builds
Node / pnpm
Use when working with frontend projects using PNPM as package manager.
pnpm install # install dependencies (whole workspace)
pnpm install --frozen-lockfile # require the lockfile to match (CI)
pnpm add zod # add a dependency
pnpm add -D vitest # add as a devDependency
pnpm add -w typescript # add at the workspace root
pnpm remove zod # remove a dependency
pnpm update --latest # update to the latest versions
pnpm dev # run the "dev" script
pnpm build # run the "build" script
pnpm run <script> # any package.json script
pnpm dlx <package> # run a package without installing it (like npx)
pnpm outdated # outdated dependencies
pnpm why <package> # why a package is installed
pnpm store prune # clean the global store
Change into different workspaces (monorepos):
pnpm -r build # run build in every package
pnpm -r --parallel dev # run dev everywhere in parallel
pnpm --filter admin dev # only the "admin" package
pnpm --filter public build # only the "public" package
pnpm --filter admin... build # admin and its internal dependencies
pnpm --filter ...shared build # shared and everything that depends on it
pnpm --filter admin add zod # add a dependency to one package
pnpm -F admin exec <command> # run a binary inside a package
Vite, SvelteKit and tests:
pnpm vite # dev server
pnpm vite build # production build
pnpm vite preview # serve the build locally
pnpm svelte-kit sync # generate SvelteKit types
pnpm svelte-check # type and a11y checks for .svelte files
pnpm svelte-check --watch
pnpm vitest # tests in watch mode
pnpm vitest run # single pass (CI)
pnpm vitest run src/tests/search.test.ts # one file
pnpm vitest -t "multiartist" # filter by test name
pnpm vitest run --coverage # coverage
Python
For FastAPI services, scripts and CLI tools.
Virtual environments with venv and pip:
python -m venv .venv # create the environment
source .venv/bin/activate # activate (Linux/macOS)
.venv\Scripts\Activate.ps1 # activate (PowerShell on Windows)
deactivate # leave the environment
pip install -r requirements.txt # install dependencies
pip install --upgrade pip
pip freeze > requirements.txt # pin versions
pip list --outdated # outdated packages
pip show <package> # package info
pip install torch --index-url https://download.pytorch.org/whl/cpu # CPU-only PyTorch (small Docker image)
With uv (faster, replaces venv + pip):
uv venv # create .venv
uv pip install -r requirements.txt
uv init # new project with pyproject.toml
uv add fastapi uvicorn # add dependencies to the project
uv sync # install according to uv.lock
uv run python tagger.py # run inside the environment
uv run pytest
uv python install 3.12 # install a Python version
FastAPI with uvicorn:
uvicorn main:app --reload # development with auto-reload
uvicorn main:app --host 0.0.0.0 --port 8000 # reachable from the network/container
uvicorn main:app --workers 2 # multiple processes (simple production)
fastapi dev main.py # FastAPI CLI alternative
Tests and code quality:
pytest # run all tests
pytest -v # verbose
pytest -x # stop at the first failure
pytest -k "genre" # filter by name
pytest tests/test_db.py::test_insert # a specific test
pytest -s # show print()
pytest --lf # only the ones that failed last time
pytest --cov=. --cov-report=term-missing # coverage (pytest-cov)
ruff check . # linter
ruff format . # formatter
python -m pip install -e . # install the project in editable mode
Databases
SQLite for local/self-hosted services; PostgreSQL for the main backend.
sqlite3 (dot-commands are typed inside the sqlite3 shell):
sqlite3 app.db # open (or create) the database
sqlite3 app.db "SELECT COUNT(*) FROM tracks;" # direct query
sqlite3 app.db < migrations/v3.sql # run a script
sqlite3 -header -column app.db "SELECT * FROM albums LIMIT 5;"
sqlite3 app.db ".backup backup.db" # consistent backup
sqlite3 app.db ".dump" > dump.sql # export as SQL
.tables -- list tables
.schema tracks -- schema of a table
.headers on
.mode column -- readable output (also: csv, json)
.read migrations/v3.sql -- run a file
.quit
PRAGMA foreign_keys = ON; -- enable foreign keys (per connection)
PRAGMA journal_mode = WAL; -- better read/write concurrency
PRAGMA integrity_check; -- verify the database
PRAGMA user_version; -- schema version
VACUUM; -- compact the file
EXPLAIN QUERY PLAN SELECT ...; -- check whether indexes are used
psql and PostgreSQL:
psql -h localhost -U user -d dbname # connect
psql "postgresql://user:password@host:5432/db" # with a connection URL
psql -d db -f schema.sql # run a file
psql -d db -c "SELECT now();" # a single command
\l -- list databases
\c dbname -- switch database
\dt -- list tables
\d products -- describe a table
\di -- indexes
\du -- roles/users
\x -- expanded output (toggle)
\timing -- show the duration of each query
\copy products TO 'products.csv' CSV HEADER -- client-side export
\q -- quit
Backups with pg_dump and restore:
pg_dump -U user -d db > backup.sql # plain SQL
pg_dump -U user -Fc -d db -f backup.dump # custom format (compressed)
pg_dump -U user -d db --schema-only > schema.sql # schema only
pg_dump -U user -d db -t products > products.sql # one table
pg_dumpall -U postgres > everything.sql # all databases + roles
psql -d db < backup.sql # restore plain SQL
pg_restore -U user -d db --clean backup.dump # restore custom format
Docker
For building and shipping services:
docker build -t myapp:latest . # build the image
docker build -t myapp:cpu -f Dockerfile.cpu .
docker build --no-cache -t myapp . # without cache
docker run --rm -p 8000:8000 myapp # run and map a port
docker run -d --name app -p 8000:8000 --env-file .env myapp # in the background
docker run --rm -it myapp bash # shell inside the image
docker run -v ${PWD}/data:/data myapp # mount a folder
docker ps # running containers
docker ps -a # all, including stopped
docker logs -f app # follow logs
docker logs --tail 100 app
docker exec -it app bash # enter a running container
docker stop app && docker rm app # stop and remove
Image size and analysis (useful when shrinking images):
docker image ls # list images with their size
docker image ls myapp # only one repository
docker history myapp # size of each layer
docker image inspect myapp --format '{{.Size}}'
docker image rm myapp:old # delete an image
docker image prune # delete untagged images
docker system df # Docker disk usage
docker system prune -a --volumes # aggressive cleanup (careful)
Docker Compose:
docker compose up # start the services
docker compose up -d --build # in the background, rebuilding
docker compose down # stop and remove
docker compose down -v # also delete volumes (deletes data)
docker compose ps
docker compose logs -f api # logs of one service
docker compose exec api bash # shell in a service
docker compose restart api
docker compose pull # update images
docker compose config # validate and print the final config
Registries and moving images between machines:
gcloud auth configure-docker us-central1-docker.pkg.dev
docker tag myapp us-central1-docker.pkg.dev/PROJECT/REPO/myapp:v1
docker push us-central1-docker.pkg.dev/PROJECT/REPO/myapp:v1
docker pull nginx:alpine
docker save -o myapp.tar myapp # export an image to a file
docker load -i myapp.tar # import it
Cloudflared
Credentials and configuration:
cat /root/.cloudflared/<tunnel-uuid>.json # tunnel credentials
cat /etc/cloudflared/config.yml # config file
Ingress rules and DNS records:
cloudflared tunnel ingress validate
cloudflared tunnel ingress rule https://www.website.com
cloudflared tunnel route dns --overwrite-dns <tunnel-uuid> www.website.com
Restart the service:
systemctl restart cloudflared
journalctl -u cloudflared -n 20 --no-pager
Nginx
cat /etc/nginx/sites-available/app1 # edit a site config
nginx -t && systemctl restart nginx # validate and restart