Node / Express
✨ How to use: Copy this entire spec and paste it into your AI assistant (Claude, ChatGPT, etc.) when asking it to prepare your project for Niblit.ai deployment.
# Niblit.ai Deployment Spec: Node.js + Express
You are deploying a Node.js Express application to Niblit.ai.
Follow these instructions EXACTLY. Do not deviate.
## Requirements
- Node.js 20 or 22
- Express as the web framework
- SQLite (better-sqlite3) for any database needs (no Postgres, no MySQL)
- App must listen on port 8080
- All persistent data must be stored in /data/ directory
## Required Project Structure
```
your-project/
├── Dockerfile ← REQUIRED (use the template below exactly)
├── package.json ← REQUIRED (must include express)
├── index.js ← REQUIRED (or app.js, server.js)
└── ... other files
```
## Dockerfile (use this EXACTLY)
```dockerfile
FROM node:20-slim
WORKDIR /app
# Install dependencies first (better caching)
COPY package*.json ./
RUN npm ci --only=production
# Copy application code
COPY . .
# Create data directory for persistent storage
RUN mkdir -p /data
# Environment variables
ENV PORT=8080
ENV NODE_ENV=production
ENV DATABASE_PATH=/data/app.db
EXPOSE 8080
# Start the application
CMD ["node", "index.js"]
```
## package.json must include
```json
{
"name": "my-app",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"express": "^4.18.0"
}
}
```
## Express App Structure (index.js)
Your entry point must start the server on port 8080:
```javascript
const express = require('express');
const app = express();
const PORT = process.env.PORT || 8080;
app.get('/', (req, res) => {
res.send('Hello from Niblit.ai!');
});
app.get('/health', (req, res) => {
res.json({ status: 'ok' });
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
```
## Database Rules
- Use SQLite ONLY (recommend `better-sqlite3` package)
- Database file MUST be stored at: `/data/app.db`
- The /data directory is persistent storage — it survives restarts and redeploys
- Everything outside /data is ephemeral and will be reset on redeploy
Example database setup with better-sqlite3:
```javascript
const Database = require('better-sqlite3');
const path = require('path');
const DATABASE_PATH = process.env.DATABASE_PATH || '/data/app.db';
const db = new Database(DATABASE_PATH);
// Initialize schema
db.exec(`
CREATE TABLE IF NOT EXISTS items (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`);
// Example queries
const getAll = db.prepare('SELECT * FROM items ORDER BY created_at DESC');
const insert = db.prepare('INSERT INTO items (name) VALUES (?)');
// Usage
const items = getAll.all();
insert.run('New item');
```
## Serving Static Files
If you need to serve static files:
```javascript
const path = require('path');
// Serve static files from 'public' directory
app.use(express.static(path.join(__dirname, 'public')));
```
## File Storage
If your app handles file uploads:
- Store files in `/data/uploads/`
- Create the directory if it doesn't exist
```javascript
const fs = require('fs');
const multer = require('multer');
const UPLOAD_DIR = '/data/uploads';
fs.mkdirSync(UPLOAD_DIR, { recursive: true });
const storage = multer.diskStorage({
destination: UPLOAD_DIR,
filename: (req, file, cb) => {
cb(null, Date.now() + '-' + file.originalname);
}
});
const upload = multer({ storage });
app.post('/upload', upload.single('file'), (req, res) => {
res.json({ filename: req.file.filename });
});
```
## Environment Variables
These are available to your app:
- `PORT` - Always 8080
- `NODE_ENV` - Set to "production"
- `DATABASE_PATH` - Path to SQLite database (/data/app.db)
## What NOT to Include
- No `.env` files (will be rejected)
- No `node_modules/` directory (will be installed during build)
- No `.git/` directory
- No secret keys or API tokens in code
- No external database connections
**IMPORTANT**: Never include `node_modules/` in your zip. It will be installed during the Docker build from your package.json.
## Testing Locally Before Upload
1. Build and run with Docker:
```bash
docker build -t my-app .
docker run -p 8080:8080 -v $(pwd)/data:/data my-app
```
2. Visit http://localhost:8080
3. If it works, create the zip and upload to Niblit.ai.
## Creating the Upload Zip
```bash
# From your project root:
zip -r my-app.zip . -x "*.git*" -x "node_modules/*" -x ".env" -x "data/*"
```
**Make sure node_modules/ is excluded!**
## Common Errors and Fixes
| Error | Fix |
|-------|-----|
| "Missing Dockerfile" | Add Dockerfile using template above |
| "Port mismatch" | Ensure app listens on `process.env.PORT` or 8080 |
| "Missing package.json" | Create package.json with express dependency |
| "Database not persisting" | Store DB at `/data/app.db`, not `./app.db` |
| "Cannot find module" | Make sure dependency is in package.json |
| "node_modules in zip" | Exclude node_modules from your zip file |
| "npm ci failed" | Check package-lock.json exists and is valid |
## Resource Limits
- **Free tier**: 256MB RAM, shared CPU, 1GB storage
- **Pro tier**: 512MB RAM, shared CPU, 1GB storage
- **Team tier**: 1GB RAM, 2 shared CPUs, 5GB storage
Free tier apps sleep after 5 minutes of no traffic and wake automatically (3-5 second cold start).
## Example App
See the `example/` directory for a complete working example.