AdonisJS & DigitalOcean: Scalable TypeScript Deployments
Modern web development demands robust backends and flexible, scalable infrastructure. This post explores integrating AdonisJS, a full-stack Node.js framework, with DigitalOcean's suite of services. We'll build a TypeScript-first application, demonstrating how to leverage managed databases, object storage, and a streamlined deployment pipeline for a production-ready setup.
AdonisJS: A Backend Powerhouse with TypeScript
AdonisJS provides a comprehensive ecosystem for building web applications, emphasizing developer experience and performance. Its first-class TypeScript support ensures type safety and better maintainability for complex projects.
First, set up a new AdonisJS project:
npm init adonis-ts-app@latest my-adonis-app
cd my-adonis-app
Let's create a simple user controller and route. Run node ace make:controller Users and add a basic index method.
// app/Controllers/Http/UsersController.ts
import type { HttpContext } from '@adonisjs/core/http'
export default class UsersController {
public async index({ response }: HttpContext) {
return response.json([
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
])
}
}
Define the route in start/routes.ts:
// start/routes.ts
import router from '@adonisjs/core/services/router'
router.get('/users', '#controllers/users_controller.index')
Managed PostgreSQL: Robust Data Storage on DigitalOcean
DigitalOcean Managed Databases offer a scalable, highly available, and secure database solution without the operational overhead. Integrating it with AdonisJS is straightforward.
Provision a PostgreSQL database instance on DigitalOcean. Once created, you'll receive connection details (host, port, user, password, database name). Update your AdonisJS .env file with these credentials:
DB_CONNECTION=pg
PG_HOST=your-do-db-host.ondigitalocean.com
PG_PORT=25060
PG_USER=doadmin
PG_PASSWORD=your_secure_password
PG_DB_NAME=your_database_name
Ensure your config/database.ts is configured to use these environment variables:
// config/database.ts
import { defineConfig } from '@adonisjs/lucid'
const dbConfig = defineConfig({
connection: 'pg',
connections: {
pg: {
client: 'pg',
connection: {
host: Env('PG_HOST'),
port: Env('PG_PORT'),
user: Env('PG_USER'),
password: Env('PG_PASSWORD'),
database: Env('PG_DB_NAME'),
ssl: { rejectUnauthorized: false } // Required for DO connections
},
migrations: { tableName: 'adonis_schema' }
}
}
})
export default dbConfig
DigitalOcean Spaces: Scalable Object Storage
DigitalOcean Spaces provides S3-compatible object storage, perfect for static assets, user uploads, and backups. AdonisJS's Drive module can easily integrate with Spaces using an S3 driver.
Install the S3 driver for AdonisJS:
npm i @adonisjs/s3-driver
node ace configure @adonisjs/s3-driver
Configure your .env with Spaces credentials (key, secret, region, endpoint, bucket name):
DRIVE_DISK=s3
S3_KEY=YOUR_SPACES_KEY
S3_SECRET=YOUR_SPACES_SECRET
S3_REGION=nyc3
S3_ENDPOINT=https://nyc3.digitaloceanspaces.com
S3_BUCKET=your-space-name
Now, you can use the Drive facade to upload files:
// app/Controllers/Http/UploadsController.ts
import type { HttpContext } from '@adonisjs/core/http'
import app from '@adonisjs/core/services/app'
import Drive from '@adonisjs/core/services/drive'
export default class UploadsController {
public async store({ request, response }: HttpContext) {
const file = request.file('avatar', { size: '2mb', extnames: ['jpg', 'png'] })
if (!file) {
return response.badRequest('No file uploaded.')
}
const fileName = `${Date.now()}.${file.extname}`
await file.move(app.tmpPath('uploads'), { name: fileName })
// Upload to DigitalOcean Spaces
const filePathInSpace = `avatars/${fileName}`
await Drive.put(filePathInSpace, file.tmpPath!)
return response.json({ message: 'File uploaded successfully', path: filePathInSpace })
}
}
Seamless Deployment with DigitalOcean App Platform
DigitalOcean App Platform simplifies deploying and scaling web applications, handling infrastructure, CI/CD, and scaling automatically. It integrates directly with your GitHub repository.
Create an app.yaml file in your project root to define your application's components and settings:
// app.yaml
name: my-adonis-app
region: nyc
services:
- name: web
github:
repo: your-github-username/my-adonis-app
branch: main
deploy_on_push: true
build_command: npm install && npm run build
run_command: node ace migration:run --force && node server.js
environment_slug: node-js
instance_size_slug: basic-s
routes:
- path: /
envs:
- key: APP_KEY
scope: RUN_TIME
value: <YOUR_ADONIS_APP_KEY>
- key: DB_CONNECTION
scope: RUN_TIME
value: pg
- key: PG_HOST
scope: RUN_TIME
value: ${DB_HOST}
- key: PG_PORT
scope: RUN_TIME
value: ${DB_PORT}
- key: PG_USER
scope: RUN_TIME
value: ${DB_USERNAME}
- key: PG_PASSWORD
scope: RUN_TIME
value: ${DB_PASSWORD}
- key: PG_DB_NAME
scope: RUN_TIME
value: ${DB_NAME}
- key: S3_KEY
scope: RUN_TIME
value: <YOUR_SPACES_KEY>
- key: S3_SECRET
scope: RUN_TIME
value: <YOUR_SPACES_SECRET>
- key: S3_REGION
scope: RUN_TIME
value: nyc3
- key: S3_ENDPOINT
scope: RUN_TIME
value: https://nyc3.digitaloceanspaces.com
- key: S3_BUCKET
scope: RUN_TIME
value: your-space-name
Link your GitHub repository to DigitalOcean App Platform, select your app.yaml, and let App Platform handle the rest. It will automatically build, deploy, and connect to your managed database and Spaces.
Conclusion: A Unified, Productive Ecosystem
Integrating AdonisJS with DigitalOcean's robust services creates a powerful, scalable, and developer-friendly stack. By leveraging Managed Databases, Spaces, and App Platform, you can focus on building features rather than managing infrastructure, ensuring your TypeScript applications are performant and resilient from development to production.