# How to Integrate Bolt.new with Docker

- Tool: Bolt.new
- Difficulty: Beginner
- Time required: 30 minutes
- Last updated: April 2026

## TL;DR

Docker cannot run inside Bolt.new's WebContainer browser environment, but you can containerize your Bolt project after exporting it. Push your Bolt project to GitHub, clone it locally, and add a Dockerfile with a multi-stage build. Run the container locally to verify it works, then deploy the Docker image to AWS ECS, Google Cloud Run, Railway, or any container platform. The exported project is a standard Node.js app that works with Docker without modification.

## Containerizing Bolt.new Projects with Docker for Production Deployment

Bolt.new's WebContainer is itself a containerization technology of sorts — it isolates your development environment inside a browser tab. But Docker containers are fundamentally different: they package a complete OS filesystem, application runtime, and code into a portable image that can be deployed to any server. You cannot run Docker inside a browser, and you cannot run Bolt's WebContainer on most Docker deployment platforms. The two technologies are complementary, not competing.

The workflow is clean and practical. You use Bolt for what it excels at — rapid AI-assisted UI development, component generation, and integration prototyping. When the app reaches a state ready for production-grade deployment, you export the code (via Bolt's GitHub integration), add Docker configuration files, and build a container image. The container can then be pushed to Docker Hub, AWS ECR, Google Container Registry, or any other container registry, and deployed to platforms like Railway, Render, Google Cloud Run, AWS ECS, or a self-managed Kubernetes cluster.

The key insight is that Bolt generates standard Vite or Next.js projects — well-understood frameworks with established Docker patterns. A multi-stage Dockerfile that builds the app in one stage and serves it in a smaller production stage is the standard approach. For Vite apps (which produce static files), you serve the output with nginx. For Next.js apps (which can include server-side rendering), you run a Node.js server. Both patterns are well-documented and the configurations below work with Bolt-generated code without modification.

## Before you start

- A Bolt.new project pushed to a GitHub repository (use Bolt's Git panel to push to GitHub first)
- Docker Desktop installed on your local machine (download at docker.com/products/docker-desktop for Mac and Windows, or Docker Engine for Linux)
- Git installed locally to clone the repository from GitHub
- Basic understanding of terminal commands (cd, ls, running commands)
- A cloud platform account for deployment: Railway (railway.app), Render (render.com), Google Cloud, or AWS — all have free tiers that support Docker containers

## Step-by-step guide

### 1. Push Your Bolt Project to GitHub and Clone Locally

Docker configuration files need to be added to your project locally — you cannot run Docker commands from Bolt's WebContainer browser environment. The first step is getting your Bolt project onto your local machine through GitHub.

In Bolt, open the Git panel and push your project to a GitHub repository if you have not already. Once the push completes, open a terminal on your local machine and clone the repository. Navigate into the project directory and install dependencies to verify the project is intact.

At this point, verify that the Bolt project builds successfully in a clean local environment by running the build command. This is an important check because Bolt's WebContainer and a local Node.js installation can sometimes behave differently — TypeScript strict mode settings, peer dependency requirements, and environment variable handling may surface issues that were hidden in Bolt's environment. Fix any build errors before proceeding to Docker configuration.

Note a critical architectural difference that Docker resolves: in Bolt's WebContainer, native Node.js modules that require compilation (like bcrypt, sharp, or canvas) fail because WebContainers enforce a no-addons flag. In a Docker container running real Node.js on Linux, these modules compile and run normally. If your Bolt project had to use JavaScript alternatives to these modules (e.g., bcryptjs instead of bcrypt), you can switch to the native version after adding Docker. However, if the app uses Supabase and only makes HTTP calls, no changes are needed — the exported code works as-is.

```
# Clone and set up the project locally:
git clone https://github.com/yourusername/your-bolt-project.git
cd your-bolt-project
npm install

# Verify the project builds without errors:
npm run build

# If build succeeds, you should see a dist/ directory (Vite)
# or a .next/ directory (Next.js)
ls -la
```

**Expected result:** The project cloned successfully, npm install completed, and npm run build produced a dist/ (Vite) or .next/ (Next.js) directory. The project is ready for Docker configuration.

### 2. Create a Dockerfile for Your Bolt Project

The Dockerfile defines how to package your Bolt app into a container image. The multi-stage build pattern is the best practice for production containers — a separate build stage with all development dependencies produces a smaller, more secure final image.

For Vite projects (Bolt's default when you ask for a React app), the output is a folder of static HTML, CSS, and JavaScript files. The most efficient way to serve these is with nginx, a high-performance web server. The build stage uses Node.js to run npm run build, and the final stage copies only the built files into an nginx container. The resulting image is typically 20-40 MB — much smaller than a Node.js-based server.

For Next.js projects (Bolt generates these when you request Next.js or server-side features), the app needs to run as a Node.js server since it may include server-side rendering or API routes. The multi-stage build installs dependencies, runs npm run build with the standalone output mode enabled in next.config.js, and the final stage runs only the standalone server output.

The Dockerfiles below are production-ready for Bolt-generated projects. Choose the appropriate one based on your project type — you can determine this by checking whether your project has a vite.config.ts (Vite) or next.config.js (Next.js) file.

```
# Dockerfile for Vite/React Bolt projects (static output served by nginx):

# Build stage
FROM node:18-alpine AS builder

WORKDIR /app

# Copy package files first for better layer caching
COPY package*.json ./
RUN npm ci --only=production=false

# Copy source files and build
COPY . .
RUN npm run build

# Production stage
FROM nginx:alpine AS production

# Copy built files from build stage
COPY --from=builder /app/dist /usr/share/nginx/html

# Copy nginx config for SPA routing
COPY nginx.conf /etc/nginx/conf.d/default.conf

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]
```

**Expected result:** A Dockerfile exists in the project root. Running 'docker build -t my-bolt-app .' should complete without errors and produce a container image.

### 3. Add Supporting Configuration Files

The Dockerfile alone is not quite complete — Vite SPAs need a special nginx configuration for client-side routing to work, and all projects benefit from a .dockerignore file to speed up builds.

For Vite Bolt projects using React Router or Wouter for navigation, nginx needs to be configured to serve index.html for all routes (not just the root path). Without this, navigating directly to a URL like /dashboard will return a 404 from nginx. The nginx.conf below fixes this with a try_files directive that falls back to index.html for any unresolved path.

The .dockerignore file is conceptually similar to .gitignore — it prevents specified directories and files from being sent to the Docker daemon as part of the build context. Including node_modules/ (typically 200-500 MB) in the build context makes every docker build command take minutes to upload, even if nothing changed. Excluding it ensures Docker only processes your source files.

For Next.js Bolt projects, you also need to update next.config.js to enable standalone output mode. This causes Next.js to output a self-contained server in .next/standalone that can be deployed without installing node_modules — making the Docker image significantly smaller and faster to start.

After adding these files, commit them to your repository and push to GitHub. Bolt will see these new files when you next pull from GitHub, so the Docker configuration becomes part of the Bolt project going forward.

```
# nginx.conf for Vite SPA routing:
server {
    listen 80;
    server_name _;
    root /usr/share/nginx/html;
    index index.html;

    # Serve static files directly, fallback to index.html for SPA routing
    location / {
        try_files $uri $uri/ /index.html;
    }

    # Cache static assets for 1 year
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # Don't cache HTML
    location ~* \.html$ {
        expires -1;
        add_header Cache-Control "no-store";
    }
}

---

# .dockerignore:
node_modules
dist
.next
build
.env
.env.local
.env.*.local
npm-debug.log*
.DS_Store
.git
.gitignore
README.md
*.md
```

**Expected result:** The nginx.conf and .dockerignore files are in the project root. Docker builds now skip node_modules and complete in 30-60 seconds. Vite SPA routes work correctly inside the container.

### 4. Add docker-compose for Local Development with a Database

If your Bolt project uses Supabase in production but you want to run a real database locally (outside Bolt's WebContainer limitations), docker-compose makes this straightforward. You can run your Bolt app container alongside a PostgreSQL container on your local machine, replicating the production architecture without any cloud services.

An important context here: in Bolt's WebContainer, you cannot use raw TCP database connections — the standard pg npm package that connects directly to PostgreSQL fails because WebContainers cannot open TCP sockets. Bolt solves this by using Supabase's HTTP-based PostgREST interface. But once you have exported your project and are running it in Docker, real TCP connections work perfectly. This means locally with Docker, you can run a PostgreSQL container and connect to it using the pg package or Prisma directly — a workflow impossible in Bolt's browser environment.

The docker-compose.yml below defines two services: your Bolt app (built from the Dockerfile) and a PostgreSQL database. The app service depends on the database, so docker-compose starts PostgreSQL first. Environment variables pass the database connection string to the app. A named volume persists the database data between container restarts so you do not lose your development data.

Note that this docker-compose setup is for local development only — it is not the recommended production deployment pattern. For production, use a managed database (Supabase, Neon, PlanetScale) and deploy the app container separately to your chosen cloud platform.

```
# docker-compose.yml for local development:
version: '3.8'

services:
  app:
    build: .
    ports:
      - '3000:80'    # Vite nginx: 80
      # - '3000:3000'  # Next.js: 3000
    environment:
      - NODE_ENV=development
      - VITE_SUPABASE_URL=http://localhost:54321  # Local Supabase alternative
      # Or use Postgres directly (requires code changes from Supabase HTTP client):
      - DATABASE_URL=postgresql://postgres:postgres@db:5432/myapp
    depends_on:
      db:
        condition: service_healthy
    volumes:
      - ./src:/app/src  # Mount src for hot-reloading (dev mode)

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
    ports:
      - '5432:5432'  # Expose for direct database client access
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U postgres']
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  postgres_data:
```

**Expected result:** Running 'docker-compose up' starts both the app and database containers. The app is accessible at http://localhost:3000 and can make real TCP database connections to the PostgreSQL container.

### 5. Deploy the Docker Image to a Cloud Platform

With a working Dockerfile, deploying to cloud container platforms is straightforward. The most developer-friendly options for Bolt projects are Railway and Render, which connect directly to your GitHub repository and build the Docker image automatically on every push. This creates the same automation you get from Bolt's publish button, but via Docker with container-platform capabilities.

For Railway: create a new project at railway.app, click 'Deploy from GitHub repo,' select the repository, and Railway automatically detects the Dockerfile and builds it. Add environment variables in Railway's 'Variables' tab (SUPABASE_URL, SUPABASE_ANON_KEY, and any other keys your app needs). Railway provides a public URL with automatic HTTPS. The Starter plan is free with limited usage.

For Google Cloud Run (for higher traffic or team use): build and push the Docker image to Google Container Registry, then create a Cloud Run service pointing to that image. Cloud Run scales to zero when not in use, making it cost-effective for Bolt prototypes that do not receive constant traffic.

Regarding the WebContainer limitation and deployment: Bolt's browser-based development environment cannot receive incoming webhooks, run persistent background processes, or use raw TCP sockets. Once your app is deployed as a Docker container, all of these work normally. If your Bolt app integrated with services that require webhooks (Stripe, GitHub Apps, Twilio), register your Docker deployment URL as the webhook endpoint — not the Bolt preview URL. Deploy first, then configure the webhook URLs.

```
# Build and push Docker image to Docker Hub (then deploy anywhere):
docker build -t yourusername/your-bolt-app:latest .
docker push yourusername/your-bolt-app:latest

# Or build and deploy to Google Cloud Run:
gcloud auth login
gcloud config set project your-project-id

docker build -t gcr.io/your-project-id/bolt-app:latest .
docker push gcr.io/your-project-id/bolt-app:latest

gcloud run deploy bolt-app \
  --image gcr.io/your-project-id/bolt-app:latest \
  --platform managed \
  --region us-central1 \
  --allow-unauthenticated \
  --set-env-vars SUPABASE_URL=https://yourproject.supabase.co
```

**Expected result:** Your Bolt app is running as a Docker container in the cloud with a public HTTPS URL. The deployment works independently of Bolt's browser environment, with full access to TCP networking, persistent storage, and webhook reception.

## Best practices

- Always use multi-stage Dockerfile builds for Bolt projects — the builder stage with all node_modules (200-500 MB) is discarded, leaving a production image of 20-50 MB that starts faster and has a smaller attack surface.
- Add a .dockerignore file before your first docker build to exclude node_modules/ and .next/ from the build context — without it, the first build can take 5+ minutes just uploading files to the Docker daemon.
- Store sensitive environment variables (API keys, database passwords) as secrets in your cloud platform's environment configuration rather than baking them into the Docker image with ARG/ENV instructions.
- Use Railway or Render for Bolt project deployments if you are new to Docker — they handle the docker build and push automatically from GitHub without requiring local Docker commands.
- Test the Docker container locally with 'docker run -p 3000:80 your-image' before pushing to a cloud platform to catch configuration issues early, especially nginx routing for Vite SPAs.
- Pin specific versions in your Dockerfile base images (FROM node:18.17-alpine instead of FROM node:18-alpine) to prevent unexpected behavior when base images update.
- Commit the Dockerfile and .dockerignore to the GitHub repository that Bolt pushes to — this keeps the Docker configuration versioned alongside the Bolt-generated code and visible in Bolt's file tree.

## Use cases

### Deploying a Bolt App to Railway or Render

Add a Dockerfile to a Bolt project and connect the GitHub repository to Railway or Render for automated container deployments. Every push from Bolt to GitHub triggers a new Docker build and deployment, giving you a production-grade URL with automatic HTTPS and environment variable management.

### Local Development with a Real Database Using docker-compose

Create a docker-compose.yml that runs your Bolt app container alongside a PostgreSQL container for local development. This replicates production conditions locally, letting you test database interactions without relying on a remote Supabase instance or worrying about the WebContainer's inability to use raw TCP database drivers.

### Consistent Deployment Environment Across Team Members

Use Docker to ensure all team members and CI/CD pipelines build and run the Bolt app in an identical environment. Eliminate 'works on my machine' issues caused by different Node.js versions or local dependencies by defining the exact runtime in the Dockerfile.

## Troubleshooting

### Docker build fails with 'exec /usr/local/bin/docker-entrypoint.sh: exec format error' on M1/M2 Mac when deploying to Linux servers

Cause: The Docker image was built on Apple Silicon (ARM64 architecture) but the deployment target is an x86_64 Linux server. The two architectures are incompatible without explicit multi-platform builds.

Solution: Use Docker's buildx command to build multi-platform images that work on both ARM and x86: 'docker buildx build --platform linux/amd64 -t your-image:latest --push .' This creates an image compatible with standard Linux cloud servers. For Railway and Render, they typically handle this automatically by building in their own Linux environment from your Dockerfile.

```
# Multi-platform build for cloud deployment from Mac:
docker buildx create --use
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t yourusername/bolt-app:latest \
  --push .
```

### The containerized Vite app returns 404 for all routes except the root path /

Cause: The default nginx configuration does not have a fallback for SPA routing. When a user navigates directly to /dashboard, nginx tries to find a file at that path, cannot find it, and returns 404 instead of serving index.html and letting React Router handle the route.

Solution: Add the nginx.conf file from Step 3 with the try_files $uri $uri/ /index.html directive. This tells nginx to serve index.html for any path that does not match a static file, allowing the React Router to handle client-side routing.

```
# nginx.conf - add this location block:
location / {
    try_files $uri $uri/ /index.html;
}
```

### Environment variables are undefined in the Bolt app after containerization, even though they are set in docker-compose.yml

Cause: Vite embeds VITE_* environment variables at build time (when npm run build runs), not at container runtime. Variables set in docker-compose.yml environment are available at runtime but Vite has already finished its build — so VITE_* vars must be present during the Docker build step, not just when the container starts.

Solution: For Vite projects: pass VITE_* variables as Docker build arguments (ARG in Dockerfile, --build-arg in docker build command) so they are available when Vite processes them during the build stage. For Next.js NEXT_PUBLIC_* variables, the same applies. Server-side environment variables (without a prefix) can be set at runtime in docker-compose.yml or on the cloud platform.

```
# Dockerfile with build args for Vite variables:
FROM node:18-alpine AS builder
WORKDIR /app

# Declare build arguments
ARG VITE_SUPABASE_URL
ARG VITE_SUPABASE_ANON_KEY

# Make them available as environment variables during build
ENV VITE_SUPABASE_URL=$VITE_SUPABASE_URL
ENV VITE_SUPABASE_ANON_KEY=$VITE_SUPABASE_ANON_KEY

COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Build with args:
# docker build \
#   --build-arg VITE_SUPABASE_URL=https://xyz.supabase.co \
#   --build-arg VITE_SUPABASE_ANON_KEY=your-key \
#   -t my-bolt-app .
```

## Frequently asked questions

### Can I run Docker inside Bolt.new's editor?

No — Docker requires a real operating system kernel to manage containers, and Bolt.new's WebContainer runs inside a browser tab. WebContainers virtualize Node.js using WebAssembly but cannot run Docker daemon processes or build container images. Docker is a post-export technology: use Bolt for development, then containerize the exported project for production deployment.

### Will native Node.js modules like bcrypt or sharp work in a Docker container after failing in Bolt?

Yes — Docker runs on real Linux (or via Docker Desktop on your local machine), so native modules that require C/C++ compilation via node-gyp install and run correctly. Bolt's WebContainer enforces a --no-addons flag that blocks these modules. If you used JavaScript alternatives (bcryptjs, jimp) in your Bolt project to work around this limitation, you can switch to the native versions after containerization if performance is a concern.

### Can I use Docker for webhooks that do not work in Bolt's preview?

Yes — once your Bolt app is running as a Docker container with a public URL, incoming webhooks work normally. Bolt's WebContainer cannot receive webhooks because it runs inside a browser tab with no public internet address. Deploy your Docker container to a cloud platform first, then register the deployment URL as the webhook endpoint in Stripe, GitHub, Twilio, or whichever service you are integrating with.

### How do I update the Docker deployment after making changes in Bolt?

The recommended workflow is: make changes in Bolt, push to GitHub using Bolt's Git panel, and then either let your CI/CD pipeline (CircleCI, Railway auto-deploy) rebuild the image automatically, or run docker build and push manually. Railway and Render can be configured to automatically rebuild and redeploy the Docker image on every GitHub push, creating a seamless Bolt-to-container pipeline.

### What is the difference between running my Bolt app in Docker locally versus in Bolt's preview?

Bolt's preview uses WebContainers (Node.js in a browser via WebAssembly) while Docker runs real Linux Node.js. The practical differences: Docker allows raw TCP database connections (so you can use pg or mongoose directly), supports native modules (bcrypt, sharp), can receive incoming webhooks if exposed, persists files between restarts with volumes, and runs the exact same environment as production. Bolt's preview is faster to iterate in but has the WebContainer constraints described above.

---

Source: https://www.rapidevelopers.com/bolt-ai-integrations/docker
© RapidDev — https://www.rapidevelopers.com/bolt-ai-integrations/docker
