Skip to content

SQLDoc

SQL-first development

A pluggable compiler pipeline for SQL schemas. Tags in comments drive code generation, migrations, and custom plugins.

sqldoc logo

See It in Action

Write standard SQL with tags in comments:

INPUT SQL
sql
-- @import '@sqldoc/ns-audit'
-- @import '@sqldoc/ns-codegen'
-- @import '@sqldoc/ns-docs'
-- @import '@sqldoc/ns-rls'
-- @import '@sqldoc/ns-validate'

-- @docs.description('User accounts for the application')
-- @audit(on: [insert])
-- @rls
-- @rls.policy(for: ALL, to: authenticated, using: 'user_id = current_setting(''app.user_id'')::int')
CREATE TABLE users (
  -- @codegen.rename('id')
  user_id SERIAL PRIMARY KEY,

  -- @validate.pattern('^.+@.+\..+$')
  email VARCHAR(100) NOT NULL,

  -- @audit.redact(strategy: omit)
  password_hash TEXT NOT NULL
);
COMPILED OUTPUT
sql
CREATE TABLE users (
  user_id SERIAL PRIMARY KEY,

  email VARCHAR(100) NOT NULL,

  password_hash TEXT NOT NULL
);

-- Generated by sqldoc
-- sqldoc: @audit(on: [insert])
CREATE TABLE IF NOT EXISTS "users_audit_log" (
  id BIGSERIAL PRIMARY KEY,
  table_name TEXT NOT NULL,
  operation TEXT NOT NULL,
  old_data JSONB,
  new_data JSONB,
  changed_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE OR REPLACE FUNCTION "users_audit_fn"() RETURNS TRIGGER AS $$
BEGIN
  INSERT INTO "users_audit_log" (table_name, operation, old_data, new_data, changed_at)
  VALUES (TG_TABLE_NAME, TG_OP, CASE WHEN TG_OP = 'INSERT' THEN NULL ELSE row_to_json(OLD) END, row_to_json(NEW), now());
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER "users_audit_trigger"
  AFTER INSERT ON "users"
  FOR EACH ROW EXECUTE FUNCTION "users_audit_fn"();
-- sqldoc: @rls
ALTER TABLE "users" ENABLE ROW LEVEL SECURITY;
-- sqldoc: @rls.policy(for: ALL, to: authenticated, using: 'user_id = current_setting(''app.user_id'')::int')
CREATE POLICY "users_authenticated_all" ON "users"
  FOR ALL
  TO authenticated
  USING (user_id = current_setting();
-- sqldoc: @validate.pattern('^.+@.+\..+$')
ALTER TABLE "users" ADD CONSTRAINT "users_email_pattern" CHECK ("email" ~ '^.+@.+\..+$');

Tags compile to correct SQL for your dialect. The original SQL stays unchanged — tags are comments.

Namespace Plugins

13 plugins covering audit trails, security, validation, documentation, and more.

Code Generation Templates

26 templates across 15 languages. Generate typed code from your SQL schema.