---
title: "Data Connect: All About Schemas"
description: "Data Connect: All About Schemas"
published: "2025-02-11"
last_updated: "2025-02-11"
authors:
  - "Andrea Wu (Developer Advocate)"
categories:
  - "SQL Connect"
  - "GraphQL"
  - "PostgreSQL"
canonical_url: "https://firebase.blog/posts/2025/02/dataconnect-schemas"
---

# Data Connect: All About Schemas

*Published February 11, 2025 by Andrea Wu (Developer Advocate)*

---
> **Note:** Firebase Data Connect has been renamed to SQL Connect. Learn more in the [SQL Connect announcement](https://firebase.blog/posts/2026/04/whats-new-sql-connect).

Many apps need to store persistent data, and most of the time, that data needs to be organized in a structured way. With Data Connect, you model your app data using schemas, and this blog post dives into what schemas are and how to use them. 

We’ll use the movie review app example you might already know from the [documentation](https://firebase.google.com/docs/data-connect/schemas-queries-mutations#movie-schema-intro) and our previous [deep-dive blog posts](https://firebase.blog/posts/2024/10/dataconnect-series-announce).

### Declaring a Schema
Firebase Data Connect schemas are [defined using GraphQL](https://firebase.blog/posts/2024/10/dataconnect-graphql). The key components of GraphQL schema definitions are:
- Type definition
- Table name
- `@table` directive, which includes the optional arguments of naming convention and key(s)

Here is an example from the [movie tracker app](https://firebase.google.com/codelabs/firebase-dataconnect-web#0):

```javascript
type Movie @table(name: "Movies", singular: "movie", plural: "movies", key: ["id"])
```

This line has:
- A `type` type definition, letting GraphQL know this is declaring a type (other examples of type definitions are `query` and `mutation`)
- `Movie` as the name of the schema
- A directive `@table` which signifies creation of a schema

Within the `@table` directive, there are a few optional fields:
- `name`: defines the table name; by default, the table name is the schema name
- `singular`: for implicit queries and mutations, this defines the name that gets used in the query / mutation that requires this table
- `plural`: for implicit mutations, this defines the name that gets used in the mutation that requires this table
- `key`: an optional list for the name of the table's key(s)

By default, the singular naming convention will be the name of the table with a lower case first letter, and the plural one will be the singular with a “s” at the end. You only need to use `singular` or `plural` to adjust the name if it is different than the default.

Similarly, the key by default will be named `id`, and you do not need to declare this when you declare a schema.

Removing all of the defaults, the above declaration can be simplified to:

```javascript
type Movie @table(name: "Movies")
```

### Anatomy of a Schema
Now that you know how to declare a schema, how does a schema in its entirety look like? It is broken down into the following parts:
- Declaration to create a schema, as described in the previous section
- List of items in the schema

Here is an example schema for movies, written verbosely with all optional fields present except the schema declaration as covered above:

```javascript
type Movie @table(name: "Movies") @index(fields: [releaseYear, rating], order: [ASC, DESC]) {
  id: UUID! @col(name: "movie_id") @default(expr: "uuidV4()")
  title: String! @col(name: "title")
  releaseYear: Int @col(name: "release_year") @index
  genre: String @col(name: "genre", dataType: "varchar(30)")
  rating: Int @col(name: "rating")
  description: String @col(name: "description")
}
```

Each line is the name of a column along with the data type of that column. Any data type followed by `!` means this attribute is required. Data Connect supports a wide range of [data types](https://firebase.google.com/docs/data-connect/schemas-queries-mutations#supported_data_types), some of which are in this code snippet like `UUID`, `String`, and `Int`. UUID is a special data type that indicates that this is a unique ID, which is useful for keys. 

We also see `@col`, `@default`, and `@index` directives:
- `@col` explicitly sets column information, including names and data type. The `genre` column is named “genre” with the String data type of at most 30 characters. By default, the first word of each line becomes the column name, so you only need `@col(name: “...”` if you want a different name.
- `@default` lets you set default values. In the example above, an `id` defaults to a UUID generated by `uuidV4()`.
- `@index` defines a database index to optimize query performance. To create a single field SQL index, put `@index` on a `@col` field. You can specify `order`, but this doesn’t matter much for single field indexes as they can be scanned in both directions. To define a composite index, You can put `@index(fields: [...])` on `@table` and define an order for each indexed column, defaulted to ASC. Above, `releaseYear` would be ordered in ascending order whereas `rating` would be ordered in descending order.

Removing all of the defaults, the above can be simplified to:

```javascript
type Movie @table(name: "Movies") @index(fields: [releaseYear, rating], order: [ASC, DESC]) {
  id: UUID! @default(expr: "uuidV4()")
  title: String!
  releaseYear: Int @index
  genre: String @col(dataType: "varchar(30)")
  rating: Int
  description: String
}
```

### Key Scalars
For databases optimized for speed, key scalars are an efficient way to identify objects. Data Connect automatically assembles these identifiers from key fields in your schemas, and the resulting scalars provide information about data identity and structure, accessible within a single cell. Key use cases include:
- sequential operations: key scalars serve as unique identifiers for new records, simplifying subsequent operations
- relational operations: key scalars provide access to relational keys, enabling more complex data manipulations

### Server Values
Sometimes, your app might need server-computed values because the values need to be computed at the time of data creation. You can do this by using server values, where the server dynamically populates fields in your tables using stored or readily-computable values according to particular server-side expressions. For example, you can define a field with a timestamp applied when the field is accessed using the expression `createdAt: Timestamp! @default(expr: "request.time")`. This might be used when a user creates their account, so the schema could look like this:

```javascript
type User @table(key: "uid") {
  // other fields
  createdAt: Date! @default(expr: "request.time")
}
```

### Relationships Between Tables
A big part of using relational databases is (surprise!): relationships between tables, and Data Connect lets you do that. [Here](https://firebase.blog/posts/2025/01/dataconnect-relationships) is an in-depth blog post on how to define one-to-one, one-to-many, and many-to-many relationships in your schemas. 

### Try it out!
Data modeling is a crucial part of any app that requires data, and hopefully this blog post clarifies how to define and use schemas in Data Connect. If you need more information about Data Connect, check out the [documentation](https://firebase.google.com/docs/data-connect), and you can also check out other deep-dive [articles](https://firebase.blog/posts/2024/10/dataconnect-series-announce). As it’s a new product, we’d love to hear your opinion and any [feature requests](https://firebase.uservoice.com/forums/948424-general?category_id=501596) you have as we’re hard at work improving and adding more features to the product. If you haven’t already, give Data Connect a try today - we can’t wait to see what you build with it!
