Keystone.js is a powerful, developer-friendly headless CMS and application framework built on Node.js. It generates a GraphQL API and admin UI from your schema definition, making it ideal for building content-managed websites and applications. This guide covers deploying Keystone.js on your VPS.
Why Keystone.js?
- Schema-driven: Define your data model in TypeScript, get a GraphQL API and admin UI automatically
- Powerful relationships: First-class support for complex data relationships
- Document field: Rich text editing with customizable blocks
- Access control: Fine-grained, field-level access control
- Extensible: Custom hooks, virtual fields, and server-side logic
Installation
# Prerequisites
sudo apt install -y postgresql nodejs npm
# Create project
cd /opt
npm init keystone-app@latest my-keystone-cms
cd my-keystone-cms
# Configure database connection
cat > .env `/images${path}`,
serverRoute: { path: '/images' },
storagePath: 'public/images',
},
},
})
Querying with GraphQL
# Fetch published posts
query {
posts(where: { status: { equals: "published" } }, orderBy: { publishedAt: desc }) {
id
title
slug
content { document }
featuredImage { url width height }
author { name }
tags { name }
publishedAt
}
}
# Fetch single post
query GetPost($slug: String!) {
post(where: { slug: $slug }) {
title
content { document }
author { name bio }
publishedAt
}
}
Build and Deploy
# Build for production
npm run build
# Create systemd service
sudo cat > /etc/systemd/system/keystone.service {
if (session) return {} // Staff sees all
return { status: { equals: 'published' } } // Public only sees published
},
},
},
// ... fields
})
Best Practices
- Use database migrations: Run
keystone prisma migratefor schema changes in production - Implement proper access control before going live — don't use
allowAllin production - Set up a CDN for image delivery from the local storage
- Use hooks for automated slug generation, validation, and side effects
- Enable GraphQL playground only in development — disable in production