Move your dev environment
Get an existing project — code, backing services, data and keys — onto a HostStack dev box. Everything here works today; where a path doesn't exist yet, the page says so.
The short version
Code comes in over git. Backing services are already in the box — you start them rather than move them. Data comes in over the network, pulled from somewhere the box can reach. Credentials go in through the dashboard or the terminal. There's no "upload my whole environment" button.
New to dev boxes? Start with AI dev environments.
Bring the code
Git is the transport. Push what you have locally to a remote, then point a box at it.
| Where the repo lives | How to get it into a box |
|---|---|
| GitHub, connected to your team | Pick it under GitHub repo when you create the box, or clone it from the terminal. No key needed: HTTPS clone and push go through your team's HostStack GitHub App, and git@github.com: remotes are rewritten to HTTPS so they use it too. |
| Any public http(s) URL | Paste it under Clone URL. The box clones it into /workspace/<repo> on first boot. Only http(s) URLs are accepted there; ssh:// and git@ URLs have to be cloned from the terminal. |
| Private, on GitLab, Bitbucket, Codeberg or your own server | Create a Blank box, add an SSH key and clone over SSH (below). The box's credential helper covers GitHub only, so an HTTPS clone from those hosts asks for credentials it can't supply. |
In the box's terminal:
# ~/.ssh points at /workspace/.ssh, so the key survives restarts.
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ''
cat ~/.ssh/id_ed25519.pub # add this as a deploy key on the host
ssh-keyscan gitlab.com >> ~/.ssh/known_hosts
git clone git@gitlab.com:acme/my-app.git /workspace/my-appGenerating the key in the box means the private half never leaves it. To use a key you already have instead, write it to ~/.ssh/id_ed25519 and chmod 600 it — there's no dashboard form for SSH keys.
Bring the backing services
You don't move these: the box already has them, as native processes rather than containers. There's no Docker daemon in a box, so a docker-compose.yml full of postgres, redis and friends is replaced, not run. Run it anyway — the box reads your compose file and tells you what to start instead:
docker compose up # prints which of YOUR services the box covers
dev-services up # postgres :5432 · redis :6379 · meilisearch :7700
dev-services up mysql mongodb # MariaDB :3306 · MongoDB :27017, only when asked for
dev-services statusThey listen on localhost only, and none of them needs a password:
| Compose image | Start it with | Connection URL |
|---|---|---|
postgres, postgis, pgvector, timescaledb | dev-services up | postgresql://dev@localhost:5432/dev |
redis, valkey, redis-stack | dev-services up | redis://localhost:6379 |
meilisearch | dev-services up | http://localhost:7700 (no master key) |
mysql, mariadb, percona | dev-services up mysql | mysql://dev@127.0.0.1:3306/<db> |
mongo, mongodb | dev-services up mongodb | mongodb://127.0.0.1:27017 |
A Postgres image's extensions (PostGIS, pgvector, TimescaleDB) are not part of the box's Postgres — the compose image maps to plain Postgres 17.
Your app's .env probably names a database and role that don't exist yet — postgres://postgres:postgres@localhost:5432/myapp is the classic. Create them rather than editing the config:
dev-services createdb myapp # database "myapp", owned by "dev"
dev-services createdb myapp postgres # …or by a "postgres" role, created if missingAnything with no in-box equivalent — Kafka, Elasticsearch, a vendor's sidecar — has to run as a HostStack service or point at a remote instance; the docker message lists which of your compose services those are. The engines keep their data on /workspace and come back by themselves after a restart.
Bring the data
The box can reach out, but nothing can reach in: there's no SSH server, so rsync, scp and sftp into a box don't work. Every import is a pull, run from the box's terminal.
- Small files
Up to 16 MB each: drag, paste or Attach in the Terminal. The file lands in
/workspace/.uploads/and its path is pasted at your cursor.- Anything larger
Put it somewhere the box can fetch — object storage with a signed URL, a release asset, a server you own — and pull it with
curl,wget,gitor an outboundscp:scp you@your-server:/backups/db.dump /workspace/works, from the box toward a host that accepts SSH.- A live database you can reach
Skip the file and stream it straight in.
dev-services up
dev-services createdb myapp
# Stream from a server you can reach…
pg_dump "postgresql://user:pw@old-host:5432/myapp" | psql -d myapp
# …or restore a dump file you pulled in
pg_restore -d myapp /workspace/myapp.dumpdev-services up mysql
mariadb -u dev -e 'CREATE DATABASE IF NOT EXISTS myapp'
mariadb-dump -h old-host -u user -p myapp | mariadb -u dev myapp# Usually not worth moving — let the cache rebuild.If the data is the point — a staging dataset you want backed up and restorable — put it in a managed database instead of the box, and link it so its URL is injected. Managed databases are backed up daily and restorable from the dashboard; /workspace is not.
hoststack db create --project prj_... --name app-db --engine postgres
hoststack db link db_... --service svc_... --alias APP
hoststack deploy trigger svc_... # a link applies on the next deploy
# Then, in the box, DATABASE_URL is set:
psql "$DATABASE_URL" -c 'select 1'Bring your credentials
- Coding-agent logins
Save one per agent under Settings → Coding agents; it's stored encrypted on your account and seeded into every box, so you never do it per box. Already signed in inside a box? Save it from Development → All dev boxes → Shared setup → Agent logins with Capture.
- API keys
ANTHROPIC_API_KEY,OPENAI_API_KEYand anything your app needs: set them in the box under Settings → Variables. The HostStack MCP key is provisioned for you.- SSH keys
No dashboard form: write them into
/workspace/.ssh/from the terminal, as above.- Git identity
A box starts with the name and email on your HostStack account as the commit author. Change it under Development → All dev boxes → Shared setup → Source control.
Bring your shell setup
Only /workspace persists. The rest of the filesystem — including $HOME and ~/.bashrc — is rebuilt from the image whenever the container is recreated: on power down and resume, a disk resize or an image update. So keep dotfiles on the volume and source them:
git clone https://github.com/you/dotfiles /workspace/.dotfiles
# For this shell, and every new one until the next restart:
echo '. /workspace/.dotfiles/bashrc' >> ~/.bashrc
. /workspace/.dotfiles/bashrcGlobal tools do persist, because the image points them at the volume:
bun add -ginstalls under/workspace/.bun, andpip install --userunder/workspace/.local— both onPATH.npm install -gdoes not persist; usebun add -g.- Runtimes added with
dev-runtime addland in/workspace/.mise. node_modules,vendorand the like are in your repo, so they're on the volume already.apt-get installcan't work in a box. If the image is missing a system package you need, ask us to add it.
A one-line setup script in your repo is still the reliable answer for a box you might recreate.
First-run checklist
See what's running
hoststack-statusshows the engines, the dev URL and the image build.Start the databases your app uses
dev-services up, plusmysqlormongodbif your stack needs them, thendev-services createdb myappto match your.env.Add a runtime, if yours isn't built in
Node, Bun, Python and PHP are there already. For anything else,
dev-runtime add go(orjava,ruby,rust,erlang,elixir,dotnet).Install and start the app on port 3000
cd /workspace/my-app && bun install && bun run dev—PORT=3000andHOST=0.0.0.0are already set.Open the dev URL
Click Open app in the box's header. A "No app is listening on port 3000 yet" page (HTTP 503) means nothing is bound to port 3000; an invalid-host error means your framework needs
.hoststack.devin its allowed hosts — see Serve your app on the dev URL.
What has no path yet
These are real gaps, listed so you can plan around them rather than look for them:
- No workspace import or restore
You can't upload a tarball of an existing environment, and there's no snapshot of a box's volume to restore from. Move code through git and data through a database.
- No inbound SSH
So no
rsyncorscpinto a box. Every transfer starts from inside it.- Uploads are small
The terminal upload is 16 MB per file — for screenshots and logs, not archives.
- No dotfile seeding
See above.
- GitHub is the only repo picker
GitLab, Bitbucket and Codeberg aren't sources in the create form, though HostStack deploys from them. Use a public clone URL, or a blank box and an SSH clone.
- Companions are always new
The create form only makes fresh companion databases. Link an existing one afterwards with
hoststack db link.- The CLI can't open a box
There's no
dev shell,dev execordev open. Use the dashboard Terminal.- No team switcher in the CLI
There's no
hoststack teamscommand. If you're on more than one team, setHOSTSTACK_TEAM_IDto choose which one CLI commands act on.- No MongoDB dump tools
mongodumpandmongorestorearen't in the image.
Next steps
Was this page helpful?