Developing Internal Tools with NocoDB (No-Code Database)
NocoDB transforms an existing relational database (PostgreSQL, MySQL, SQLite) into an Airtable-like interface. Key difference from Baserow—NocoDB connects to an already existing database and displays real tables, rather than creating a separate storage.
Key Advantages
- Connects to existing PostgreSQL/MySQL—data stays there
- Open-source (AGPL), self-hosted
- Spreadsheet interface for non-technical staff over production data
- REST and GraphQL API out of the box
- Forms for data collection without code
Installation
# Docker
docker run -d \
--name nocodb \
-v nocodb_data:/usr/app/data \
-p 8080:8080 \
nocodb/nocodb:latest
# With external PostgreSQL connection
docker run -d \
-e NC_DB="pg://host:port?u=user&p=password&d=database" \
-p 8080:8080 \
nocodb/nocodb:latest
Connection to Production PostgreSQL
After starting NocoDB → Add Connection → PostgreSQL:
Host: 10.0.1.50
Port: 5432
Database: app_production
User: nocodb_readonly
Password: ****
Schema: public
NocoDB automatically imports all schema tables. For tables with FK, relationships are displayed (Link to another record).
Important: create a separate readonly user for tables that shouldn't be edited:
-- View-only for most tables
GRANT SELECT ON ALL TABLES IN SCHEMA public TO nocodb_readonly;
-- Allow editing only for specific tables
GRANT SELECT, INSERT, UPDATE ON customer_notes TO nocodb_rw;
GRANT SELECT, UPDATE ON users TO nocodb_rw;
NocoDB REST API
# NocoDB automatically generates API for each table
# Swagger UI: http://localhost:8080/api/v1/meta/tables/TABLE_ID
# List records with filter
GET /api/v1/db/data/noco/{PROJECT_ID}/{TABLE_ID}?where=(status,eq,active)&limit=25&offset=0
# Create record
POST /api/v1/db/data/noco/{PROJECT_ID}/{TABLE_ID}
{"name": "John", "email": "[email protected]", "status": "new"}
# Bulk update
PATCH /api/v1/db/data/bulk/noco/{PROJECT_ID}/{TABLE_ID}
[{"id": 1, "status": "processed"}, {"id": 2, "status": "processed"}]
Forms for Data Collection
NocoDB allows creating a public form from any table—via link users fill the form, data is recorded in the table. Useful for:
- Customer requests (external form → leads table)
- Employee forms (reports, requests)
- Feedback collection
Automation via Webhook
// NocoDB Webhook → your server on row change
app.post('/hooks/nocodb/leads', async (req, res) => {
const { type, data } = req.body;
if (type === 'records.after.insert') {
const lead = data.insertedRows[0];
// Create contact in CRM
await crmApi.createContact({
email: lead.Email,
name: lead.Name,
phone: lead.Phone
});
// Notify manager in Telegram
await telegramBot.sendMessage(MANAGER_CHAT_ID,
`New request from ${lead.Name} (${lead.Email})`
);
}
res.sendStatus(200);
});
Timeline
Connection to existing database + permission setup + initial interfaces — 1–2 days.







