DEV Community

Cover image for How to Dockerize and Deploy Astro
Jonas Scholz
Jonas Scholz Subscriber

Posted on

How to Dockerize and Deploy Astro

If you're just here to copy and paste, here's the final Dockerfile that will produce an image for your Astro app:

FROM node:20-alpine AS base
WORKDIR /app

# By copying only the package.json and package-lock.json here, we ensure that the following `-deps` steps are independent of the source code.
# Therefore, the `-deps` steps will be skipped if only the source code changes.
COPY package.json package-lock.json ./

FROM base AS prod-deps
RUN npm install --omit=dev

FROM base AS build-deps
RUN npm install

FROM build-deps AS build
COPY . .
RUN npm run build

FROM base AS runtime
COPY --from=prod-deps /app/node_modules ./node_modules # Copy dependencies
COPY --from=build /app/dist ./dist # Copy the built output

# Bind to all interfaces
ENV HOST=0.0.0.0
# Port to listen on
ENV PORT=4321
# Just convention, not required
EXPOSE 4321

CMD node ./dist/server/entry.mjs # Start the app
Enter fullscreen mode Exit fullscreen mode

And here's the .dockerignore file:

.DS_Store
node_modules
dist
Enter fullscreen mode Exit fullscreen mode

To build and run the image, use these commands:

docker build -t astro .
docker run -p 4321:4321 astro
Enter fullscreen mode Exit fullscreen mode

Not just here to copy and paste? Let's go over what's happening in the Dockerfile!

yeah

The Setup

For this tutorial, I assume you have a basic Astro project set up. If you have a different setup, you might need to adjust the Dockerfile accordingly.

Typically, you'd run npm install and then npm run dev to work locally. However, for deployment, we want to build the app and serve the files from a server. So instead, we'll use npm run build to create the files and then serve them.

Let's dive into the details of the Dockerfile.

The Dockerfile

FROM node:20-alpine AS base
WORKDIR /app

# By copying only the package.json and package-lock.json here, we ensure that the following `-deps` steps are independent of the source code.
# Therefore, the `-deps` steps will be skipped if only the source code changes.
COPY package.json package-lock.json ./

FROM base AS prod-deps
RUN npm install --omit=dev

FROM base AS build-deps
RUN npm install

FROM build-deps AS build
COPY . .
RUN npm run build

FROM base AS runtime
COPY --from=prod-deps /app/node_modules ./node_modules # Copy dependencies
COPY --from=build /app/dist ./dist # Copy the built output

# Bind to all interfaces
ENV HOST=0.0.0.0
# Port to listen on
ENV PORT=4321
# Just convention, not required
EXPOSE 4321

CMD node ./dist/server/entry.mjs # Start the app
Enter fullscreen mode Exit fullscreen mode

So what's happening here?

  1. Base stage:
    • Uses Node.js 20 on Alpine, providing a lightweight base image.
    • Sets up the working directory and copies package files for dependency installation.
  2. Production dependencies stage:
    • Installs only production dependencies, omitting dev dependencies.
  3. Build dependencies stage:
    • Installs all dependencies, including dev dependencies needed for building.
  4. Build stage:
    • Copies the entire project and runs the build command.
  5. Runtime stage:
    • Starts from the base image again.
    • Copies production dependencies and built files from previous stages.
    • Sets environment variables for host and port.
    • Exposes port 4321 (Astro's default port).
    • Starts the Astro app using the built server entry point.

This multi-stage approach optimizes the build process and keeps the final image size smaller by separating build and runtime environments.
Make sure to add the .dockerignore file to ignore the node_modules and dist folders. This will speed up the build process and reduce the image size.

Deployment

You can deploy this Docker container to any cloud provider that supports Docker. For example, you could use platforms like Heroku, DigitalOcean, or AWS ECS. Because I am the co-founder of Sliplane, I will show you how to deploy it there.

After signing up, you can create a new service by selecting your Github Repository. Then just keep the default settings and click on deploy.

Create Service

After deployment your astro app will be available under a subdomain of sliplane.app, usually its just your service name.

You can also see the logs of your app, see metrics such as cpu and memory usage, add persistant storage and much more. Whenever you push to your repository, Sliplane will automatically deploy your app.

If you want to try out Sliplane, the first 2 days are free! Try it out and let me know what you think :)

Next Steps

Is there anything else you want to know? Do you need help dockerizing your Astro app? Do you need help deploying it to a specific platform? Feel free to reach out!
You can find me on X or just comment here on this blog.

Cheers,

Jonas

Top comments (3)

Collapse
 
wimadev profile image
Lukas Mauser • Edited

Collapse
 
code42cate profile image
Jonas Scholz

Collapse
 
thecodingthesi profile image
Thesi

Astro is so cool ngl