Skip to content
/ srtd Public
forked from t1mmen/srtd

๐Ÿช„ Supabase migrations made magical: Live-reloading SQL + Sane, reviewable diffs + Maintainable templates = Delightful DX

License

Notifications You must be signed in to change notification settings

damassi/srtd

ย 
ย 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

57 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

srtd ๐Ÿช„ Supabase Repeatable Template Definitions

Live-reloading SQL templates for Supabase projects. DX supercharged! ๐Ÿš€

NPM Version Downloads License: MIT CI/CD codecov

video demo

srtd enhances the Supabase DX by adding live-reloading SQL templates into local db. The single-source-of-truth template โžก๏ธ migrations system brings sanity to code reviews, making git blame useful.

๐Ÿ“– Blog: Introducing srtd: Live-Reloading SQL Templates for Supabase

Why This Exists ๐Ÿค”

While building Timely's next-generation Memory Engine on Supabase, we found ourselves facing two major annoyances:

  1. Code reviews were painful - function changes showed up as complete rewrites, git blame was useless
  2. Designing and iterating on database changes locally was full of friction, no matter which workflow we tried

I spent nearly two years looking for something pre-existing, to no avail. Sufficiently fed up, I paired with Claude to eliminate these annoyances.

Say hello to srtd.

screenshot of srtd

Key Features โœจ

  • Live Reload: Changes to your SQL templates instantly update your local database
  • Single Source of Truth: Templates are the source of all (non-mutable) database objects, improving code-review clarity
  • Just SQL: Templates build as standard Supabase migrations when you're ready to deploy
  • Developer Friendly: Interactive CLI with visual feedback for all operations

Built specifically for projects using the standard Supabase stack (but probably works alright for other Postgres-based projects, too).

Requirements

  • Node.js v20.x or higher
  • Supabase CLI installed and project initialized (with /supabase directory)
  • Local Postgres instance running (typically via supabase start)

Quick Start ๐Ÿš€

Installation

# Global installation
npm install -g @t1mmen/srtd

# Project installation
npm install --save-dev @t1mmen/srtd

# Or run directly
npx @t1mmen/srtd

Setup

cd your-supabase-project
npx @t1mmen/srtd init # Creates srtd.config.json, not required

Create Your First Template

Create supabase/migrations-templates/my_function.sql:

CREATE OR REPLACE FUNCTION my_function()
RETURNS void AS $$
BEGIN
  -- Your function logic here
END;
$$ LANGUAGE plpgsql;

Development Workflow

  1. Start watch mode:
npx @t1mmen/srtd watch  # Changes auto-apply to local database
  1. When ready to deploy:
npx @t1mmen/srtd build     # Creates timestamped migration file
supabase migration up      # Apply using Supabase CLI

Tip

To reduce noise in PR's, consider adding migration-templates/*srtd*.sql linguist-generated=true to your .gitattributes file. (unless you manually edit the generated files)

The Power of Templates ๐Ÿ’ช

Without templates, the smallest change to a function would show up as a complete rewrite in your version control system. With templates, the diff is clear and concise.

Perfect For ๐ŸŽฏ

โœ… Database functions:

  -- Event notifications
  CREATE OR REPLACE FUNCTION notify_changes()
  RETURNS trigger AS $$
  BEGIN
    PERFORM pg_notify(
      'changes',
      json_build_object('table', TG_TABLE_NAME, 'id', NEW.id)::text
    );
+   RAISE NOTICE 'Notified changes for %', TG_TABLE_NAME; -- Debug logging
    RETURN NEW;
  END;
  $$ LANGUAGE plpgsql;

โœ… Row-Level Security (RLS):

  -- Replace/update policies safely
  DROP POLICY IF EXISTS "workspace_access" ON resources;
  CREATE POLICY "workspace_access" ON resources
    USING (workspace_id IN (
      SELECT id FROM workspaces
      WHERE organization_id = auth.organization_id()
+       AND auth.user_role() NOT IN ('pending')
    ));

โœ… Views for data abstraction:

  CREATE OR REPLACE VIEW active_subscriptions AS
  SELECT
    s.*,
    p.name as plan_name,
    p.features
  FROM subscriptions s
  JOIN plans p ON p.id = s.plan_id
-  WHERE s.status = 'active';
+  WHERE s.status = 'active'
+    AND s.expires_at > CURRENT_TIMESTAMP;

โœ… Roles and Permissions:

  -- Revoke all first for clean state
  REVOKE ALL ON ALL TABLES IN SCHEMA public FROM public;

  -- Grant specific access
  GRANT USAGE ON SCHEMA public TO authenticated;
  GRANT SELECT ON ALL TABLES IN SCHEMA public TO authenticated;
+ GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO admin;

โœ… Safe Type Extensions:

 DO $$
 BEGIN
   -- Add new enum values idempotently
   IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'notification_type') THEN
     CREATE TYPE notification_type AS ENUM ('email', 'sms');
   END IF;

   -- Extend existing enum safely
   ALTER TYPE notification_type ADD VALUE IF NOT EXISTS 'push';
   ALTER TYPE notification_type ADD VALUE IF NOT EXISTS 'pusher';
   ALTER TYPE notification_type ADD VALUE IF NOT EXISTS 'webhook';
+  ALTER TYPE notification_type ADD VALUE IF NOT EXISTS 'email';
 END $$;

Not Recommended For

  • โŒ Table structures
  • โŒ Indexes
  • โŒ Data modifications
  • โŒ Non-idempotent operations

Use regular Supabase migrations for these cases.

Commands ๐ŸŽฎ

Interactive Mode

Running npx @t1mmen/srtd without arguments opens an interactive menu:

  • ๐Ÿ—๏ธ srtd build [--force] - Generate migrations from templates
  • โ–ถ๏ธ srtd apply [--force] - Apply templates directly to local database
  • โœ๏ธ srtd register [file.sql...] - Mark templates as already built
  • ๐Ÿš€ srtd promote - [file.sql ...] - Promote WIP template to buildable templates
  • ๐Ÿ‘€ srtd watch - Watch and auto-apply changes
  • ๐Ÿงน srtd clean - Remove all logs and reset config

Important

watch and apply commands modify your local database directly and don't clean up after themselves. Use with caution!

Configuration ๐Ÿ“

srtd.config.json created during initialization:

{
  // Prevents building templates with this extension
  "wipIndicator": ".wip",

  // Migration file naming: 20211001000000_srtd-my_function.sql
  "migrationPrefix": "srtd",

  // Template discovery
  "filter": "**/*.sql",

  // Migration file comments
  "banner": "You very likely **DO NOT** want to manually edit this generated file.",
  "footer": "",

  // Wrap migrations in transaction
  "wrapInTransaction": true,

  // File paths
  "templateDir": "supabase/migrations-templates",
  "migrationDir": "supabase/migrations",
  "buildLog": "supabase/migrations-templates/.buildlog.json",
  "localBuildLog": "supabase/migrations-templates/.buildlog.local.json",

  // Database connection
  "pgConnection": "postgresql://postgres:postgres@localhost:54322/postgres"
}

Other Features ๐Ÿ”ง

Work in Progress Templates

Add .wip.sql extension to prevent migration generation:

my_function.wip.sql  # Only applied locally, never built

Make a WIP template buildable as migration by renaming it, or using the promote command:

npx @t1mmen/srtd promote my_function.wip.sql

Template State Management

Two state tracking files:

  • .buildlog.json - Migration build state (commit this)
  • .buildlog.local.json - Local database state (add to .gitignore)

Register Existing Objects

Registering a template is useful when you're creating templates for what is already in your database. This avoids generating migrations on build (until they're changed)

# Register specific template
npx @t1mmen/srtd register my_function.sql another_fn.sql

# Interactive multi-select UI
npx @t1mmen/srtd register

Development ๐Ÿ› ๏ธ

Local Setup

# Clone and install
git clone https://github.com/stokke/srtd.git
cd srtd
npm install

# Development
npm run dev     # Watch mode
npm test        # Run tests
npm start       # Run CLI
npm start:link  # Build, npm link, and run CLI

# Quality Checks
npm run typecheck       # Type checking
npm run lint            # Lint and fix
npm run format          # Format code
npm run test:coverage   # Test coverage

Contributing ๐Ÿค

While feature-complete for our needs, we welcome:

  • ๐Ÿ› Bug fixes and reliability improvements
  • ๐Ÿ“š Documentation improvements
  • โœ… Test coverage enhancements
  • โšก๏ธ Performance optimizations

Contribution Process

  1. Create a changeset (npm run changeset)
  2. Ensure tests pass (npm test)
  3. Follow existing code style
  4. Update documentation

Note: New features are evaluated based on alignment with project scope.

Built With ๐Ÿ› ๏ธ

Terminal UI

License

MIT License - see LICENSE file.


Made with ๐Ÿช„ by Timm Stokke & Claude Sonnet

"Buy Me A Coffee"

About

๐Ÿช„ Supabase migrations made magical: Live-reloading SQL + Sane, reviewable diffs + Maintainable templates = Delightful DX

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • TypeScript 97.5%
  • Shell 2.0%
  • Other 0.5%