
Firebase Data Connect
Model Postgres-backed app data with Firebase Data Connect GraphQL schemas, auth-aware tables, and example queries for a real feature slice.
Overview
Firebase Data Connect is an agent skill for the Build phase that models Postgres-backed APIs using GraphQL schemas, relationships, and auth-scoped queries for Firebase Data Connect apps.
Install
npx skills add https://github.com/firebase/agent-skills --skill firebase-data-connectWhat is this skill?
- End-to-end Movie Review-style schema with User, Movie, Actor, Review, and join tables
- Demonstrates @table, @unique, @index, and many-to-many keys in GraphQL
- Shows auth.uid defaults and PUBLIC vs authenticated @auth query levels
- Includes one-to-one MovieMetadata and user-owned Review uniqueness patterns
- Serves as a copy-paste template for SQL Connect / Data Connect greenfield apps
- Complete Movie Review App schema example with User, Movie, Actor, Review, and join entities
Adoption & trust: 73.2k installs on skills.sh; 345 GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
You need a relational Firebase backend but only have vague Firestore document shapes and no GraphQL schema for agents to extend.
Who is it for?
Builders starting a content or marketplace app who want SQL-style schemas and review/user ownership patterns on Firebase Data Connect.
Skip if: Teams needing only document NoSQL without migrations, or production ops runbooks with zero schema design yet.
When should I use this skill?
Use when scaffolding or extending Firebase Data Connect GraphQL schemas and example queries for SQL-backed Firebase apps.
What do I get? / Deliverables
You leave with working schema and query examples—typed tables, joins, and @auth levels—that seed your Data Connect service and client SDK generation.
- schema.gql entity and relation definitions
- queries.gql with @auth levels
- Reference patterns for indexes and uniqueness
Recommended Skills
Journey fit
Backend construction is where typed schemas, relations, and @auth queries must exist before the client or agent can ship features. Backend subphase covers persistent data models and API-shaped access patterns—not UI or deploy automation.
How it compares
Schema-and-query patterns for Firebase Data Connect—not a generic REST OpenAPI generator or Firestore rules-only skill.
Common Questions / FAQ
Who is firebase-data-connect for?
Solo developers and small teams using agentic IDEs to stand up Firebase backends with relational models, especially when SKILLS examples beat reading raw reference docs alone.
When should I use firebase-data-connect?
During Build backend work when defining GraphQL types, indexes, and auth levels before wiring a Next.js or mobile client to generated Data Connect operations.
Is firebase-data-connect safe to install?
It is documentation-style schema guidance without inherent malware risk, but generated schemas affect production data access—review Security Audits on this page and validate @auth levels before deploy.
SKILL.md
READMESKILL.md - Firebase Data Connect
# Examples Complete, working examples for common SQL Connect use cases. --- ## Movie Review App A complete schema for a movie database with reviews, actors, and user authentication. ### Schema ```graphql # schema.gql # Users type User @table(key: "uid") { uid: String! @default(expr: "auth.uid") email: String! @unique displayName: String createdAt: Timestamp! @default(expr: "request.time") } # Movies type Movie @table { id: UUID! @default(expr: "uuidV4()") title: String! releaseYear: Int genre: String @index rating: Float description: String posterUrl: String createdAt: Timestamp! @default(expr: "request.time") } # Movie metadata (one-to-one) type MovieMetadata @table { movie: Movie! @unique director: String runtime: Int budget: Int64 } # Actors type Actor @table { id: UUID! @default(expr: "uuidV4()") name: String! birthDate: Date } # Movie-Actor relationship (many-to-many) type MovieActor @table(key: ["movie", "actor"]) { movie: Movie! actor: Actor! role: String! # "lead" or "supporting" character: String } # Reviews (user-owned) type Review @table @unique(fields: ["movie", "user"]) { id: UUID! @default(expr: "uuidV4()") movie: Movie! user: User! rating: Int! text: String createdAt: Timestamp! @default(expr: "request.time") } ``` ### Queries ```graphql # queries.gql # Public: List movies with filtering query ListMovies($genre: String, $minRating: Float, $limit: Int) @auth(level: PUBLIC) { movies( where: { genre: { eq: $genre }, rating: { ge: $minRating } }, orderBy: [{ rating: DESC }], limit: $limit ) { id title genre rating releaseYear posterUrl } } # Public: Get movie with full details query GetMovie($id: UUID!) @auth(level: PUBLIC) { movie(id: $id) { id title genre rating releaseYear description metadata: movieMetadata_on_movie { director runtime } actors: actors_via_MovieActor { name } reviews: reviews_on_movie(orderBy: [{ createdAt: DESC }], limit: 10) { rating text createdAt user { displayName } } } } # User: Get my reviews query MyReviews @auth(level: USER) { reviews(where: { user: { uid: { eq_expr: "auth.uid" }}}) { id rating text createdAt movie { id title posterUrl } } } ``` ### Mutations ```graphql # mutations.gql # User: Create/update profile on first login mutation UpsertUser($email: String!, $displayName: String) @auth(level: USER) { user_upsert(data: { uid_expr: "auth.uid", email: $email, displayName: $displayName }) } # User: Add review (one per movie per user) mutation AddReview($movieId: UUID!, $rating: Int!, $text: String) @auth(level: USER) { review_upsert(data: { movie: { id: $movieId }, user: { uid_expr: "auth.uid" }, rating: $rating, text: $text }) } # User: Delete my review mutation DeleteReview($id: UUID!) @auth(level: USER) { review_delete( first: { where: { id: { eq: $id }, user: { uid: { eq_expr: "auth.uid" }} }} ) } ``` ### Realtime Queries ```graphql # queries.gql (realtime additions) # Auto-refresh: this single-entity lookup refreshes automatically # when any mutation modifies this specific movie. No @refresh needed. query GetMovie($id: UUID!) @auth(level: PUBLIC) { movie(id: $id) { id title genre rating releaseYear description metadata: movieMetadata_on_movie { director runtime } reviews: reviews_on_movie(orderBy: [{ createdAt: DESC }], limit: 10) { rating text createdAt user { displayName } } } } # Event-driven: Simple refresh when any movie is added query ListMoviesSimple @auth(level: PUBLIC) @refresh(onMutationExecuted: { operation: "AddMovie" }) { movies { id title } } # Counterpart mutation for ListMoviesSimple mutation AddMovie($title: String!) @auth(level: USER) { movie_insert(data: { title: $title }) } # Event-driven: Refresh only when a movie of the same genre is added # Demonstrates the use of 'condition' and 'mutat