Deploying Your First App
Pick your runtime and configure your build. HostStack handles the rest.
Supported Runtimes
Select your runtime when creating a service. HostStack auto-detects build tools where possible. You can also bring your own Dockerfile for any language.
Build & Start Commands
Configure your install, build, and start commands in service settings. Here are common examples:
Build Command: npm run build
Start Command: npm startBuild Command: pip install -r requirements.txt
Start Command: gunicorn app:app --bind 0.0.0.0:$PORTBuild Command: go build -o server .
Start Command: ./serverBuild Command: bundle install
Start Command: bundle exec rails server -p $PORTBuild Command: mix deps.get && mix release
Start Command: _build/prod/rel/my_app/bin/my_app startBuild Command: dotnet publish -c Release -o out
Start Command: dotnet out/MyApp.dllBuild Command: composer install --no-dev
Start Command: php -S 0.0.0.0:$PORT -t publicBuild Command: ./mvnw -q -DskipTests package
Start Command: java -jar target/my-app.jar --server.port=$PORTDocker Deploys
If your language isn't natively supported or you need custom system dependencies, add a Dockerfile to your repo and select the Docker runtime. HostStack will build your image and deploy the resulting container.
FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
EXPOSE $PORT
CMD ["node", "server.js"]Zero-Downtime Deploys
HostStack uses zero-downtime rolling deploys. When you deploy, a new container starts alongside the current one. Once the new container passes health checks, traffic switches over. The old container is gracefully stopped. Your users never see downtime.
Environment Variables
Set environment variables in the Settings tab. They're encrypted at rest and available during build and runtime. See the Environment Variables guide for details.
Health Checks
HostStack checks your service is healthy before routing traffic. Set a health check path (e.g., /health) in your service settings. The endpoint should return HTTP 200 when your app is ready.
healthcheck:
path: /health
interval: 10s
timeout: 5s
retries: 3If no health check path is set, HostStack will check that your container starts and listens on the configured port.
Build Cache
HostStack caches your build dependencies between deploys. For Node.js, this means node_modules is cached. For Python, pip packages are cached. This significantly speeds up subsequent builds. Cache is cleared when your lock file changes.
Database Migrations
Run your migrations as part of the service start command (e.g., npm run migrate && node server.js). They execute inside the new container before traffic switches, so a broken migration fails the deploy and the previous version keeps serving.
Each successful application emits a migration.applied activity-log event (visible in the dashboard activity feed and via the MCP list_activity_log tool), so you can tell a "no-op redeploy" apart from a "ran a fresh migration" without grepping deploy logs.
Seed migrations bypass app-layer caches
When a migration writes data directly to Postgres (seed rows, content backfills, lookup-table updates), it doesn't go through your application code, so any Redis / in-memory cache that fronts those rows will keep serving stale data until it expires or is explicitly flushed. If your app caches the affected reads, flush the relevant prefix at the end of the migration script:
// At the end of your data-seed migration:
import { redis } from './redis';
await redis.del(...(await redis.keys('seo:*')));Troubleshooting
Build fails with "command not found"
Ensure your build command matches your runtime. For Node.js, check that your package.json has a build script defined.
App crashes on startup with "EADDRINUSE"
Your app must listen on the port specified by the PORT environment variable. Don't hardcode a port number.
Container killed: out of memory (OOM)
Your service is exceeding its size's memory limit. Resize to a larger instance size, reduce memory usage, or check for memory leaks in your application.
Build is slow (>5 minutes)
Check if your .gitignore excludes large files. Make sure you're using a lock file (package-lock.json, yarn.lock, etc.) for consistent, cached installs.
Next: Custom Domains