Deploying a Fastify App
Fastify is a highly performant, low-overhead web framework for Node.js that prioritizes speed and developer experience. With its powerful plugin architecture, built-in schema validation, rapid startup times, and minimal overhead, Fastify is the ideal choice for building fast, scalable APIs and microservices. It’s trusted by organizations that require high throughput and low latency, making it perfect for production environments where performance is critical.
This comprehensive guide walks you through deploying a Fastify application to Klutch.sh, covering both automatic Nixpacks-based deployments and Docker-based deployments. You’ll learn installation steps, explore sample code, configure environment variables, and discover best practices for production deployments.
Table of Contents
- Prerequisites
- Getting Started: Install Fastify
- Sample Code Examples
- Project Structure
- Deploying Without a Dockerfile (Nixpacks)
- Deploying With a Dockerfile
- Environment Variables & Configuration
- Plugins & Performance Optimization
- Troubleshooting
- Resources
Prerequisites
To deploy a Fastify application on Klutch.sh, ensure you have:
- Node.js 18 or higher - Fastify requires a modern Node.js version for optimal performance
- npm or yarn - For managing dependencies
- Git - For version control
- GitHub account - Klutch.sh integrates with GitHub for continuous deployments
- Klutch.sh account - Sign up for free
Getting Started: Install Fastify
Create a New Fastify Project
Follow these steps to create and set up a new Fastify application:
-
Create a new directory for your project and initialize npm:
Terminal window mkdir my-fastify-appcd my-fastify-appnpm init -y -
Install Fastify and development dependencies:
Terminal window npm install fastifynpm install --save-dev nodemonThe
nodemonpackage helps with development by automatically restarting your server when files change. -
Create a basic Fastify server. Create a file called `index.js`:
const fastify = require('fastify')({ logger: true });const port = process.env.PORT || 3000;const host = process.env.HOST || '0.0.0.0';fastify.get('/', async (request, reply) => {return { message: 'Hello from Fastify on Klutch.sh!' };});fastify.get('/api/health', async (request, reply) => {return {status: 'healthy',timestamp: new Date().toISOString(),uptime: process.uptime()};});fastify.listen({ port, host }, (err, address) => {if (err) {fastify.log.error(err);process.exit(1);}fastify.log.info(`Server running at ${address}`);});
-
Update your `package.json` with startup scripts:
{"name": "my-fastify-app","version": "1.0.0","description": "Fastify app deployed on Klutch.sh","main": "index.js","scripts": {"start": "node index.js","dev": "nodemon index.js"},"dependencies": {"fastify": "^4.24.0"},"devDependencies": {"nodemon": "^3.0.1"}}
-
Test your app locally:
Terminal window npm run devVisit http://localhost:3000 to see your app running. Check the health endpoint at http://localhost:3000/api/health.
Sample Code Examples
Basic Fastify Server with Multiple Routes
Here’s a more complete example with multiple routes, request validation, and error handling:
const fastify = require('fastify')({ logger: true });
fastify.get('/', async (request, reply) => { return { message: 'Welcome to Fastify on Klutch.sh!' };});
fastify.get('/api/health', async (request, reply) => { return { status: 'healthy', uptime: process.uptime(), timestamp: new Date().toISOString() };});
fastify.get('/api/users/:id', async (request, reply) => { const { id } = request.params; return { id: parseInt(id), name: 'John Doe', email: 'john@example.com' };});
fastify.post('/api/users', { schema: { body: { type: 'object', required: ['name', 'email'], properties: { name: { type: 'string' }, email: { type: 'string', format: 'email' } } } } }, async (request, reply) => { const { name, email } = request.body; return { id: Math.floor(Math.random() * 1000), name, email }; });
fastify.setErrorHandler((error, request, reply) => { fastify.log.error(error); reply.status(500).send({ error: 'Internal server error' });});
fastify.listen({ port: process.env.PORT || 3000, host: '0.0.0.0'}, (err, address) => { if (err) { fastify.log.error(err); process.exit(1); }});Fastify with Plugins
const fastify = require('fastify')({ logger: true });
// Register a custom pluginfastify.register(async function routes(fastify) { fastify.get('/api/version', async (request, reply) => { return { version: '1.0.0' }; });});
// Register popular pluginsfastify.register(require('@fastify/cors'));fastify.register(require('@fastify/helmet'));fastify.register(require('@fastify/jwt'), { secret: process.env.JWT_SECRET || 'your-secret-key'});
fastify.listen({ port: process.env.PORT || 3000, host: '0.0.0.0'}, (err, address) => { if (err) throw err; console.log(`Server running at ${address}`);});Fastify with Database Connection
const fastify = require('fastify')({ logger: true });
fastify.decorate('db', null);
fastify.addHook('onReady', async () => { // Initialize database connection fastify.db = { query: async (sql) => { // Your database query logic here return []; } };});
fastify.get('/api/data', async (request, reply) => { const data = await fastify.db.query('SELECT * FROM data'); return { data };});
fastify.listen({ port: process.env.PORT || 3000, host: '0.0.0.0'}, (err, address) => { if (err) throw err;});Project Structure
A typical Fastify project has this structure:
my-fastify-app/├── node_modules/├── routes/ # Route handlers│ ├── index.js│ ├── api.js│ └── users.js├── plugins/ # Custom plugins│ ├── database.js│ └── authentication.js├── utils/ # Utility functions│ ├── logger.js│ └── validators.js├── .env # Environment variables (not committed)├── .gitignore├── index.js # Main application file├── package.json└── package-lock.jsonDeploying Without a Dockerfile
Klutch.sh uses Nixpacks to automatically detect and build your Fastify application. This is the simplest deployment option that requires no additional configuration files.
- Push your Fastify application to a GitHub repository with all your source code, `package.json`, and `package-lock.json` files.
- Log in to your Klutch.sh dashboard.
- Create a new project and give it a name (e.g., "My Fastify API").
-
Create a new app with the following configuration:
- Repository: Select your Fastify GitHub repository and the branch to deploy
- Traffic Type: Select HTTP (for web applications serving HTTP traffic)
- Internal Port: Set to 3000 (the default port for Fastify applications)
- Region: Choose your preferred region for deployment
- Compute: Select the appropriate compute resource size
- Instances: Choose how many instances to run (start with 1 for testing)
- Environment Variables: Add any environment variables your app needs (database URLs, API keys, secrets, etc.)
If you need to customize the start command or build process, you can set Nixpacks environment variables:
START_COMMAND: Override the default start command (e.g.,node index.js)BUILD_COMMAND: Override the default build command
- Click "Create" to deploy. Klutch.sh will automatically detect your Node.js project, install dependencies, and start your Fastify application.
- Once deployed, your app will be available at a URL like `example-app.klutch.sh`. Test it by visiting the URL in your browser and checking the health endpoint at `/api/health`.
Deploying With a Dockerfile
If you prefer more control over the build and runtime environment, you can use a Dockerfile. Klutch.sh will automatically detect and use any Dockerfile in your repository’s root directory.
-
Create a `Dockerfile` in your project root:
# Multi-stage build for optimized Fastify deploymentFROM node:18-alpine AS builderWORKDIR /app# Copy package filesCOPY package*.json ./# Install dependenciesRUN npm ci# Production stageFROM node:18-alpineWORKDIR /app# Copy built dependencies from builderCOPY --from=builder /app/node_modules ./node_modulesCOPY --from=builder /app/package*.json ./# Copy application codeCOPY . .# Set production environmentENV NODE_ENV=production# Expose port (must match your app's listening port)EXPOSE 3000# Health checkHEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \CMD node -e "require('http').get('http://localhost:3000/api/health', (r) => {if (r.statusCode !== 200) throw new Error(r.statusCode)})"# Start the applicationCMD ["npm", "start"]
-
Create a `.dockerignore` file to exclude unnecessary files from the Docker build:
node_modulesnpm-debug.logdistbuild.git.gitignoreREADME.md.env.env.local.vscode.idea.DS_Store
- Push your code (with Dockerfile and .dockerignore) to GitHub.
-
Follow the same deployment steps as the Nixpacks method:
- Log in to Klutch.sh
- Create a new project
- Create a new app pointing to your GitHub repository
- Set the traffic type to HTTP and internal port to 3000
- Add any required environment variables
- Click “Create”
Klutch.sh will automatically detect your Dockerfile and use it to build and deploy your application.
- Your deployed app will be available at `example-app.klutch.sh` once the build and deployment complete.
Environment Variables & Configuration
Fastify applications can use environment variables for configuration. Set these in the Klutch.sh dashboard during app creation or update them afterward.
Common Environment Variables
# Server configurationPORT=3000HOST=0.0.0.0NODE_ENV=production
# Database connectionDATABASE_URL=postgresql://user:password@db.example.com:5432/mydb
# API Keys and SecretsAPI_KEY=your_api_key_hereSECRET_KEY=your_secret_key_hereJWT_SECRET=your_jwt_secret_here
# CORS configurationCORS_ORIGIN=https://yourdomain.com
# Application settingsLOG_LEVEL=infoDEBUG=falseUsing Environment Variables in Your App
const fastify = require('fastify')({ logger: { level: process.env.LOG_LEVEL || 'info' }});
const port = process.env.PORT || 3000;const host = process.env.HOST || '0.0.0.0';const nodeEnv = process.env.NODE_ENV || 'development';const jwtSecret = process.env.JWT_SECRET;
fastify.get('/config', async (request, reply) => { return { environment: nodeEnv, hasJwtSecret: !!jwtSecret, port: port };});
fastify.listen({ port, host }, (err, address) => { if (err) { fastify.log.error(err); process.exit(1); } fastify.log.info(`Server running in ${nodeEnv} mode at ${address}`);});Customizing Build and Start Commands with Nixpacks
If using Nixpacks deployment without a Dockerfile, you can customize build and start commands by setting environment variables:
BUILD_COMMAND: npm run buildSTART_COMMAND: npm startSet these as environment variables during app creation on Klutch.sh.
Plugins & Performance Optimization
Popular Fastify Plugins
Fastify’s plugin ecosystem makes it easy to add common functionality:
const fastify = require('fastify')({ logger: true });
// Security pluginsfastify.register(require('@fastify/helmet'));fastify.register(require('@fastify/cors'));
// Authenticationfastify.register(require('@fastify/jwt'), { secret: process.env.JWT_SECRET || 'your-secret-key'});
// Cachingfastify.register(require('@fastify/redis'), { url: process.env.REDIS_URL || 'redis://localhost:6379'});
// Request validationfastify.register(require('@fastify/swagger'));fastify.register(require('@fastify/swagger-ui'));
fastify.listen({ port: 3000, host: '0.0.0.0' });Horizontal Scaling
Klutch.sh makes it easy to scale your Fastify application:
- Multiple Instances: Set the number of instances in the app configuration to distribute traffic across multiple containers
- Load Balancing: Klutch.sh automatically load balances traffic across all instances
- Stateless Design: Ensure your application is stateless so it can run on multiple instances
- Shared Resources: Use external services (Redis, databases) for shared state across instances
Performance Optimization Tips
- Use Fastify’s Built-in Compression: Fastify automatically handles compression for responses
- Connection Pooling: If using databases, implement connection pooling to manage resources efficiently
- Caching Strategy: Implement caching for frequently accessed data using Redis or similar
- Async/Await: Use async/await properly to handle non-blocking operations
- Request Validation: Use Fastify’s schema validation to catch errors early
- Logging: Configure appropriate log levels to avoid performance impact
Example with optimizations:
const fastify = require('fastify')({ logger: { level: process.env.LOG_LEVEL || 'warn' }});
// Register compression pluginfastify.register(require('@fastify/compress'));
// Register caching pluginfastify.register(require('@fastify/caching'), { serverExpiresIn: 3600});
// Custom route with validationfastify.get('/api/users/:id', { schema: { params: { type: 'object', properties: { id: { type: 'integer' } } } } }, async (request, reply) => { return { id: request.params.id, name: 'John Doe' }; });
fastify.listen({ port: 3000, host: '0.0.0.0' });Troubleshooting
Application Won’t Start
Problem: Deployment completes but the app shows as unhealthy
Solution:
- Check that your app listens on port 3000 (or the port you specified)
- Verify that
process.env.PORTis properly used in your code - Ensure the
startscript inpackage.jsoncorrectly starts your app - Check application logs in the Klutch.sh dashboard for error messages
- Verify that
hostis set to0.0.0.0instead oflocalhost
Build Fails with “Cannot find module”
Problem: Dependencies are not installed during build
Solution:
- Ensure your
package.jsonis in the root directory - Verify all dependencies are listed in
dependencies, not justdevDependencies - Check that dependency names are spelled correctly
- Ensure
package-lock.jsonexists and is up to date
Port Already in Use
Problem: Error about port 3000 already being in use
Solution:
- Make sure only one instance of your app is running
- Check that previous processes are properly terminated
- Verify the PORT environment variable is being used correctly
High Memory Usage
Problem: App uses excessive memory and gets killed
Solution:
- Check for memory leaks in your application code
- Implement proper cleanup for connections and event listeners
- Monitor memory usage during development with the
--inspectflag - Consider increasing the compute tier or number of instances
Slow Response Times
Problem: Requests are responding slowly despite Fastify’s performance
Solution:
- Check for synchronous operations that should be async
- Implement caching for frequently accessed data
- Enable compression middleware to reduce payload size
- Profile your application to identify bottlenecks
- Consider upgrading your compute tier
Resources
- Fastify Official Website
- Fastify Documentation
- Fastify Plugins Guide
- Fastify Testing Guide
- Nixpacks Documentation
- Klutch.sh Dashboard
- Node.js Documentation
Summary
Deploying a Fastify application on Klutch.sh is straightforward whether you choose Nixpacks or Docker. Both methods provide reliable, scalable hosting for your high-performance APIs and microservices. Start with Nixpacks for simplicity and quick deployments, or use Docker for more control over your build environment. With Klutch.sh’s easy scaling, automatic load balancing, and environment variable management, you can deploy your Fastify app from development to production and scale it to handle millions of requests with minimal latency.