TechEarl

How to Run Anything on Your Computer Without Installing It (a Docker Reference Guide)

Try a database, a CLI tool, an old version of PHP, a whole Linux distro — without installing anything on your machine. One Docker command, gone when you're done, nothing left behind. Plus the per-tool recipes.

Ishan KarunaratneIshan Karunaratne⏱️ 9 min readUpdated
Share thisCopied

There are two reasons people install software on their dev machine: they need it long-term, or they need it for the next 30 minutes. The second case is almost always better served by running it in Docker — try the thing, prove it does what you want, and walk away with a clean machine when you're done.

This is the hub article for that pattern. The shape is one docker run command, optionally with a persistent volume for state, that you can copy-paste, replace with your version of choice, and run. No package manager, no PATH, no leftovers in /usr/local. The article links to the specific per-tool recipes for the cases where you want more (a persistent database, a configured web server, a built Dockerfile).

How do I run software without installing it on my computer?

bash
docker run --rm -it IMAGE_NAME [COMMAND]

That's the whole pattern. --rm deletes the container the moment it exits so nothing is left behind. -it gives you an interactive terminal if the tool needs one. IMAGE_NAME is whatever you want to run — an official image from Docker Hub usually exists. For a one-shot CLI tool that produces output and quits, drop the -it:

bash
docker run --rm IMAGE_NAME command

The rest of this page is the variations: how to mount your current directory so the tool can see your files, how to expose a port so your browser can reach a server you started in a container, how to keep data around between runs (databases), and how to actually use this for the most-searched cases.

Jump to:

The basic pattern

A throwaway shell inside an Ubuntu container:

bash
docker run --rm -it ubuntu:24.04 bash

When you exit, the container is gone. Try cat /etc/os-release, install something with apt, write a file in /tmp — none of it persists. The next docker run is a fresh container.

Same shape for a quick Python REPL on a specific version without touching system Python:

bash
docker run --rm -it python:3.13 python

Or a quick jq invocation on JSON without installing jq:

bash
echo '{"a": 1}' | docker run --rm -i ghcr.io/jqlang/jq '.a'

The pattern is docker run --rm [flags] IMAGE [command]. Everything else in this article is the flags that matter for specific cases.

Bind-mounting your working directory

Most tools need to see your files. Mount the current directory and set it as the working directory:

bash
docker run --rm -v "$(pwd):/work" -w /work IMAGE command

-v "$(pwd):/work" maps the current host directory to /work inside the container. -w /work sets /work as the container's working directory, so the command runs against your files.

Examples that come up constantly:

bash
# Format JSON files in place with jq
docker run --rm -v "$(pwd):/work" -w /work ghcr.io/jqlang/jq -i '.' file.json

# Run npm install for a Node project without Node installed
docker run --rm -v "$(pwd):/work" -w /work node:22 npm install

# Run pytest against a Python project
docker run --rm -v "$(pwd):/work" -w /work python:3.13 sh -c 'pip install -r requirements.txt && pytest'

# Run terraform plan
docker run --rm -v "$(pwd):/work" -w /work hashicorp/terraform plan

Two things to watch:

  • File ownership. By default the container runs as root, so any files it creates on the bind mount are owned by root on your host. Add -u $(id -u):$(id -g) to run as your user.
  • Mac / Windows performance. Bind mounts in Docker Desktop go through a virtualized filesystem; large directories can feel slow. For dev workflows that touch thousands of files, named volumes (or moving the project into your WSL2 filesystem on Windows) help. See Why Bind Mounts Are Slow on Mac and Windows.

Exposing a port (for servers)

When the thing you're running is a server (database, web server, API), publish its port:

bash
docker run --rm -p HOST_PORT:CONTAINER_PORT IMAGE

Examples:

bash
# Nginx on http://localhost:8080
docker run --rm -p 8080:80 nginx:alpine

# PostgreSQL listening on localhost:5432, no persistence (dies when you stop it)
docker run --rm -e POSTGRES_PASSWORD=hello -p 5432:5432 postgres:16

# Redis on localhost:6379
docker run --rm -p 6379:6379 redis:alpine

Container port on the right, host port on the left. The container always listens on its own port; the host port is what your browser or local app uses to reach it.

For databases, this throwaway form is fine for quick tests but loses everything on exit. That's the next section.

Persistence (for databases)

The instant a container exits with --rm, every byte in its writable layer is gone. For databases, that's everything you've created. The fix is a named volume:

bash
docker run -d --name CONTAINER_NAME \
  -p HOST_PORT:CONTAINER_PORT \
  -v VOLUME_NAME:/data/path/inside/container \
  IMAGE

Three changes from the throwaway form:

  • -d instead of --rm — runs detached, so the container survives the shell.
  • --name — gives you a stable handle for docker stop, docker start, docker logs.
  • -v NAME:/path — a named volume that Docker manages, persistent across container removal.

Walk through with Postgres:

bash
# First run — creates the volume, initializes the database
docker run -d --name pg \
  -p 5432:5432 \
  -e POSTGRES_PASSWORD=hello \
  -v pgdata:/var/lib/postgresql/data \
  postgres:16

# Use it. Connect with psql, run queries, create tables.

# Stop and remove the container
docker stop pg
docker rm pg

# Start a NEW Postgres container against the SAME volume
docker run -d --name pg \
  -p 5432:5432 \
  -e POSTGRES_PASSWORD=hello \
  -v pgdata:/var/lib/postgresql/data \
  postgres:16

# All your tables are still there.

The named volume pgdata survives container removal. Deletes only happen when you explicitly docker volume rm pgdata or docker volume prune it.

The same shape works for every persistent service — the only thing that changes is which path inside the container is the "data dir":

  • MySQL / MariaDB: /var/lib/mysql
  • PostgreSQL: /var/lib/postgresql/data
  • MongoDB: /data/db
  • Redis: /data (plus --appendonly yes to actually enable persistence)
  • Elasticsearch: /usr/share/elasticsearch/data
  • MinIO: /data

Each per-tool recipe below has the right path baked in.

Running as your user, not root

When you bind-mount your project and the container writes files, those files are owned by whatever UID the container ran as — root by default. That leaves root-owned files on your host. Annoying, occasionally a real problem.

bash
# Run as your UID and GID
docker run --rm -u "$(id -u):$(id -g)" -v "$(pwd):/work" -w /work IMAGE command

Some images don't tolerate arbitrary UIDs (Postgres official image is one), so this trick is best for build / processing / CLI containers, not databases. For databases, set permissions on the host directory before mounting, or use a named volume so Docker manages ownership.

Per-tool recipes

Each of these links to a full article with the working command, the persistence section, a practical-usage example, and the common pitfalls for that specific tool.

Databases:

Web servers and apps:

Language runtimes:

Operating systems and shells:

Dev tooling:

Common pitfalls

  • Forgetting --rm and ending up with a graveyard. A week later docker ps -a is a long list of stopped one-shot containers. Either add --rm from the start or docker container prune periodically.
  • Skipping the volume on a database. First docker rm removes the container, all your data goes with it. Always name a volume for stateful services.
  • Bind-mounting and getting root-owned files on the host. Add -u "$(id -u):$(id -g)" for build / processing containers, or accept that you'll occasionally need sudo chown to clean up.
  • Port conflicts. "Port is already in use" because something else (a previous container, a host process, another tool) is bound to the same port. docker ps to find another container; lsof -i :PORT for host processes. See Port is Already Allocated.
  • Apple Silicon and amd64-only images. Some vendor images don't ship arm64 builds. They run under emulation (slower) or fail with "exec format error." See exec format error — Apple Silicon and Multi-Arch Docker Images.

FAQ

Sources

Authoritative references this article was fact-checked against.

TagsDockerRun Without InstallingContainersSandboxDevOpsCLI

Found this useful? Pass it on.

Copied
Ishan Karunaratne

Ishan Karunaratne

Tech Architect · Software Engineer · AI/DevOps

Tech architect and software engineer with 20+ years building software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Currently Chief Technology Officer at a healthcare tech startup, which is where most of these field notes come from.

Keep reading

Related posts