→ From Coder to Shipper
From Coder to Shipper · DevOps

Package managers — apt, pip, choco, cargo

The app store for your machine: install, update, and pin versions of every tool and library — without ever building from source.

← / → to navigate · EN/VI switch below

The big picture

A package manager is the app store for software

You stop hunting for installers. You name what you need; a trusted catalog delivers it — together with everything it depends on.

An app store for software

The same idea as a phone app store, but for your terminal: thousands of ready-made programs, tested and versioned.

Installs and updates

One command installs a program; one command updates everything you have. No installer wizards, no next-next-next.

Handles dependencies

Most software needs other software to work. The manager figures that out and installs the missing pieces for you.

From a trusted registry

Packages come from a curated registry the OS or language community maintains — not a random download from the internet.

The why

Install, don't build from source

Building from source means downloading code and compiling it yourself — for a program with 40 dependencies, that's a weekend project. Installing is one command.

Building from source

You download the raw code, install every dependency yourself in the right order, compile, and fix the errors. Possible — but nobody does it anymore.

Like building a car from scratch in your garage.

Installing from a registry

Someone else already solved the dependency mess and packaged the result. You get a ready binary at a known version — in seconds, with one command.

Like buying a car from a dealership.

The core idea

What a package actually is

Four ingredients — and the manager's whole job is to handle all of them for you.

The program itself

nginx, git, flask… compiled and ready to run.

Its dependencies

Everything the program needs to work, recursively — the manager resolves the whole tree.

An exact version

Not "the latest" but 3.0.2 — so you always know exactly what you got.

A known origin

It came from a named registry (Ubuntu repos, PyPI, crates.io) — so you can re-install the same thing on any machine.

The core idea

The core loop, in four moves

Every manager in this deck plays the same game — only the names of the moves differ.

  1. 1

    You name a package

    One line: apt install nginx · pip install flask · cargo add serde.

  2. 2

    The manager resolves dependencies

    It looks the package up in the registry's index and works out everything it and its dependencies need.

  3. 3

    It installs exact versions

    Download, verify, place in the right spot — the program and its whole dependency tree.

  4. 4

    You pin, for reproducibility

    requirements.txt and Cargo.toml record exactly what you used, so the same setup can be rebuilt anywhere.

Nobody builds software from source anymore. You declare what you need — and a package manager delivers it, at a pinned version, on any machine.
the whole topic in one sentence
01
Part 1

apt — the OS-level manager

Debian/Ubuntu's manager: this is where your system tools — nginx, docker, git, curl — come from.

apt · scope

apt manages the whole operating system

It's not a Python or Rust tool — it manages the machine itself, for every user and every language.

System-wide, one manager

A single apt for the entire machine. If a program runs on your OS, apt can install it — nginx, docker, git, curl, htop… the OS toolbox of this course.

.deb files

Debian packages: a .deb is a package you could also grab by hand. The apt command just automates that — with dependency resolution on top.

Slow and steady

OS packages are tested against your distribution before they're offered — so they move slower than language packages, but rarely break your machine.

apt · the catalog

Why apt update before apt install

The mental model behind every apt workflow: your machine keeps a local copy of the catalog; the registry keeps the real one.

apt update — refresh the catalog

Downloads the index of what's available and in which versions. Installs nothing — it only updates your view of the store.

apt install — shop from the catalog

Installs from your local index. If it's stale, you might get an old version — which is exactly why you update first.

apt upgrade — update what you have

Brings every installed package to the latest version in the catalog. Your whole machine, one command.

apt · everyday commands

Five commands cover daily apt

This is 90% of what you'll ever type.

bash
# refresh the catalog, then install nginx
sudo apt update
sudo apt install nginx

# remove / update everything / see what's installed
sudo apt remove nginx
sudo apt upgrade
apt list --installed | grep nginx

sudo = run as admin — needed to touch system files. The last line just filters the installed list.

apt · in the terminal

Installing nginx, for real

Update the catalog, then buy. Watch how much the manager does for you.

ops@vps — zsh
$ sudo apt update
Reading package lists... Done
All package lists are up to date.
$ sudo apt install nginx
The following NEW packages will be installed:
nginx
Setting up nginx (1.24.0-2) ...
$ apt list --installed | grep nginx
nginx/jammy,now 1.24.0-2 amd64 [installed]
the catalog knew exactly what to fetch
02
Part 2

pip — Python's package manager

Millions of Python packages on PyPI — plus two superpowers: venv for isolation, pinning for reproducibility.

pip · the front door

PyPI: the Python app store

pip is the client; PyPI is the store. When you pip install flask, you're buying from PyPI.

Millions of packages

flask, requests, pandas, numpy… if it's Python, someone packaged it. pip install <name> and it's on your machine in seconds.

The default registry is PyPI — pip already knows where to look.

The global mess problem

By default pip installs into your system Python. Project A needs flask 2, project B needs flask 3 — they fight over one shared shelf.

The fix: a private shelf per project — venv, next slide.

pip · pinning

requirements.txt — the project's shopping list

A small text file that turns "works on my machine" into "works everywhere".

requirements.txt
# the exact versions this project was built with
flask==3.0.2
requests==2.31.0
gunicorn==21.2.0

# rebuild this exact setup anywhere:
# pip install -r requirements.txt

== pins the exact version. Fresh machine + this file = the same environment, every time.

pip · venv workflow

One isolated environment per project

Create a private environment, work in it, and record what you used.

ops@vps — zsh
$ python -m venv .venv
$ source .venv/bin/activate
(.venv) $ pip install -r requirements.txt
Collecting flask==3.0.2
Successfully installed flask-3.0.2 gunicorn-21.2.0
(.venv) $ pip freeze > requirements.txt
every project gets its own shelf — no more fights
pip · the two superpowers

venv and pinning — isolation and reproducibility

Two superpowers, one job each: venv keeps projects apart; pinning keeps "yesterday" apart from "today".

venv — isolation

A venv is a private Python environment for one project: its own folder, its own packages. Activate it and pip installs there — not into the system.

flask 2 in project A and flask 3 in project B coexist on the same machine.

Pinning — reproducibility

pip freeze writes every installed package with its exact version into requirements.txt. Anyone, any machine: pip install -r and they get your exact environment.

This is why requirements.txt lives in git.

03
Part 3

choco — Windows' package manager

Chocolatey brings the "one command installs it" magic to Windows — plus winget, the newer one built into Windows.

choco · scope

The app store for your Windows machine

Same mental model as apt — different OS. Chocolatey is the community store; winget is Microsoft's built-in.

choco — the community store

choco install git, choco install ffmpeg… installs both CLI tools and full GUI apps from the community Chocolatey repository.

winget — built into Windows

Windows 10/11 ship with winget, Microsoft's own package manager, with an official catalog: winget install Git.Git.

Same mental model

Name it — it installs with its dependencies; one command updates everything. The OS changes, the idea doesn't.

choco · everyday commands

Two commands, two managers

On Windows you'll mostly type one or the other — same muscle memory.

bash
# Chocolatey (community) — CLI tools and GUI apps
choco install git -y
choco install ffmpeg -y

# winget (built into Windows 10/11)
winget install Git.Git
winget upgrade --all

-y = yes to all prompts. winget upgrade --all updates everything at once — the apt upgrade of Windows.

04
Part 4

cargo — Rust's manager and build tool

Rust's package manager is also its build tool: one program that fetches, compiles, runs, and tests your code and its crates.

cargo · the double role

pip installs; cargo also builds

Python packages ship pre-built, so pip only installs. Rust compiles from source, so cargo builds too — and that's a feature.

Package manager

cargo add serde declares a dependency; cargo build fetches it from crates.io — Rust's registry — along with everything it depends on.

crate = Rust's package; crates.io = Rust's PyPI.

Build tool

cargo build compiles, cargo run builds and runs, cargo test runs the tests. One tool drives the whole lifecycle — you never invoke the compiler yourself.

cargo new myapp even scaffolds a ready project — Cargo.toml included.

cargo · the manifest

Cargo.toml — the project's declaration

The manifest: who the project is, and what it depends on. Cargo reads it to both install and build.

Cargo.toml
[package]
name = "myapp"
version = "0.1.0"

[dependencies]
serde = "1.0"
reqwest = "0.11"

Like requirements.txt, but versions here are minimums — cargo resolves the newest compatible ones and locks them in Cargo.lock.

cargo · in the terminal

Create, build, run

From an empty directory to a running Rust program in three commands.

ops@vps — zsh
$ cargo new myapp && cd myapp
$ cargo run
Compiling myapp v0.1.0
Finished dev [unoptimized + debuginfo] in 1.02s
Running `target/debug/myapp`
Hello, world!
the first build compiles everything; later builds are fast
Big picture · scope

Two levels of package managers

OS-level managers run the machine; language-level managers run one language's world. A real project uses both — they cooperate, they don't compete.

🖥 OS-level — the machine

apt · choco · winget

Installs and updates the machine itself: system tools (git, curl, nginx), language runtimes (python3, rust), GUI apps. One per machine, shared by everyone.

scope: the whole OS

🐍🦀 Language-level — one language's world

pip (PyPI) · cargo (crates.io)

Manages the dependencies of programs written in one language: libraries your app imports, at pinned versions. Typically one per project — inside a venv.

scope: one language's registry

apt installs python3 · pip then installs flask inside it · choco sets up the same on Windows — different layers, one machine.

Big picture · the four

The four managers at a glance

Same four moves everywhere: name it, resolve it, install it, pin it.

ManagerLevelRegistryInstallPinning
aptOS · Debian/UbuntuUbuntu / Debian reposapt install nginxthe repo versions on the machine
pipLanguage · PythonPyPIpip install flaskrequirements.txt
chocoOS · WindowsChocolateychoco install git— (per machine)
cargoLanguage · Rustcrates.iocargo buildCargo.toml + Cargo.lock
Big picture · why multiple

Why several managers, not one

It's not redundancy — it's scope.

Different scopes

apt/choco own the machine (system tools, runtimes, apps); pip/cargo own one language's dependency world. One tool can't cleanly do both.

Different registries

Each ecosystem has its own catalog, package format, and versioning rules — .deb, .whl, .crate. Each manager speaks its registry's language.

Different update rhythms

OS packages are tested against your distribution and move slowly; language packages ship daily. Both rhythms coexist on one machine.

Big picture · reproducibility

Pinning is what makes a setup reproducible

The difference between "it works here" and "it works anywhere" is a small text file in git.

requirements.txt — Python

pip freeze writes the exact versions you tested into requirements.txt. Commit it to git; any teammate or CI server rebuilds your environment with pip install -r.

No more "works on my machine".

Cargo.toml + Cargo.lock — Rust

Cargo.toml declares what you want; the auto-generated Cargo.lock records the exact versions cargo chose. Commit both, and every build uses the same crates.

Same idea, different files — pin, commit, reproduce.

Big picture · working together

One project, all four managers

Setting up the course's Flask app — every manager in its own lane.

  1. 1

    apt — the machine

    sudo apt install git python3 python3-venv curl — the OS-level toolbox, once per machine.

  2. 2

    choco / winget — the Windows teammate

    The same toolbox on a Windows machine: choco install git python curl — so everyone starts from the same ground.

  3. 3

    pip — the project

    python -m venv .venv, then pip install -r requirements.txt — the app's exact Python dependencies, isolated.

  4. 4

    cargo — the Rust parts

    For Rust services in the same project: cargo build fetches and compiles the crates — pinned by Cargo.lock.

Big picture · out of scope

What we're deliberately skipping

Package managers have deep toolboxes. These are real — but not your next step.

Building from source

Compiling software yourself from raw code. A last resort when a package doesn't exist — or when you're being very specific.

apt sources & mirrors

Configuring where Ubuntu fetches packages from (sources lists, mirrors, PPAs). You'll touch this only when chasing a specific package.

cargo features & profiles

Optional dependency sets and build profiles (debug/release tweaks). Useful later, invisible for now.

apt-get, dist-upgrade & co.

The older apt-get spelling and the heavier dist-upgrade. apt is the modern front door — stick with it.

You don't download software anymore. You declare what you need — and a manager delivers it, at a pinned version, on any machine.
the shipper's shopping habit

Name it. Install it. Pin it.

Next: your first real project — where apt, pip and a text editor finally work together.