Powersync no foreign keys on sync backend
Skill kjuhwa/skills-hub/skills/powersync/powersync-no-foreign-keys-on-sync-backend
Skip composite foreign-key constraints on a PowerSync-style backend schema and use plain text columns for cross-table references, so partial syncs don't fail and encrypted columns don't block writes.From its SKILL.md
npx -y skills add kjuhwa/skills-hub --skill powersync-no-foreign-keys-on-sync-backendAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
2.3 KB, 363 tokens by cl100k_base, as published. Nobody here has run it
When to use
You are modelling PowerSync-synced Postgres tables where some parent tables have composite primary keys like (id, user_id). The natural instinct is to add a matching composite foreign key from children. Don't.
Steps
- Declare the child column as a plain text column:
modeId: text('mode_id'). No.references(), noforeignKey(). - Enforce relationships on the frontend — SQLite queries already JOIN there, and that's where business logic lives in a PowerSync app.
- Skip indexes on the foreign-key column. Only
user_idgets an index on the backend. - For default-data tables that ship with predefined IDs, expect children to temporarily point at a default parent ID that isn't yet synced on a brand-new device; the reconcile-defaults step will populate it.
- Validate referential integrity at the application layer (DAL or service), not the database.
Counter / Caveats
- Confidence is
mediumbecause this inverts the default relational-DB advice; teams coming from a traditional stack often push back. Document the decision prominently inAGENTS.mdor a schema comment. - You lose cascade-delete at the database level. If you rely on ON DELETE CASCADE, you must replicate it in the DAL or accept orphaned rows (which PowerSync tolerates by design during partial syncs).
- If the backend gains non-sync query endpoints (admin, analytics) in the future, add FKs per-endpoint in a separate schema rather than the shared PowerSync schema.
Evidence
docs/composite-primary-keys-and-default-data.md:56-99- Example callouts:
chatThreadsTable.modeId references modesTable without foreignKey()
What ships with it: 1 file
1.4 KB alongside SKILL.md
- content.md1.4 KB