Firebase SQL Connect client SDKs let you call your server-side queries and mutations directly from a Firebase app. You generate a custom client SDK in parallel as you design the schemas, queries and mutations you deploy to your SQL Connect service. Then, you integrate methods from this SDK into your client logic.
As we've mentioned elsewhere, it's important to note that SQL Connect queries and mutations are not submitted by client code and executed on the server. Instead, when deployed, SQL Connect operations are stored on the server like Cloud Functions. This means you need to deploy corresponding client-side changes to avoid breaking existing users (for example, on older app versions).
That's why SQL Connect provides you with a developer environment and tooling that lets you prototype your server-deployed schemas, queries and mutations. It also generates client-side SDKs automatically, while you prototype.
When you've iterated updates to your service and client apps, both server- and client-side updates are ready to deploy.
If you followed the Get started, you were introduced to the overall development flow for SQL Connect. In this guide, you'll find more detailed information about generating Android SDKs from your schema and working with client queries and mutations.
To summarize, to use generated Android SDKs in your client apps, you'll follow these prerequisite steps:
Then:
Set up SDK generation:
connector.yamlSet up and use the SQL Connect emulator and iterate.
Use the Firebase CLI to set up SQL Connect generated SDKs in your apps.
The init command should detect all apps in the current folder and install
generated SDKs automatically.
firebase init dataconnect:sdk
If you have SQL Connect VS Code extension installed, it will always keep generated SDKs up to date.
If you don't use SQL Connect VS Code extension, you can use Firebase CLI to keep generated SDKs up to date.
firebase dataconnect:sdk:generate --watchYou can use the Firebase CLI to generate SQL Connect SDKs in CI/CD build processes.
firebase dataconnect:sdk:generateTo set up your client code to use SQL Connect and your generated SDK, first follow the standard Firebase setup instructions.
Then, add the following into the plugins section in app/build.gradle.kts:
// The Firebase team tests with version 1.8.22; however, other 1.8 versions,
// and all newer versions are expected work too.
kotlin("plugin.serialization") version "1.8.22" // MUST match the version of the Kotlin compiler
Then, add the following into the dependencies section in
app/build.gradle.kts:
implementation(platform("com.google.firebase:firebase-bom:34.14.1"))
implementation("com.google.firebase:firebase-dataconnect")
implementation("com.google.firebase:firebase-auth") // Optional
implementation("com.google.firebase:firebase-appcheck") // Optional
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") // Newer versions should work too
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.5.1") // Newer versions should work too
Initialize your SQL Connect instance using the information you used to set up SQL Connect. Find this information in the Databases & Storage > SQL Connect page of the Firebase console.
The SDK requires a connector configuration object.
This object is automatically generated from serviceId and location in
dataconnect.yaml, and connectorId in connector.yaml.
Now that you've set up a configuration object, get a SQL Connect
connector instance. The code for your connector will be generated by the
SQL Connect emulator. If your connector name is movies and the
Kotlin package is com.myapplication, as specified in connector.yaml, then
retrieve the connector object by calling:
val connector = com.myapplication.MoviesConnector.instance
With the connector object, you can run queries and mutations as defined in the GraphQL source code. Suppose your connector has these operations defined:
mutation createMovie($title: String!, $releaseYear: Int!, $genre: String!, $rating: Int!) {
movie_insert(data: {
title: $title
releaseYear: $releaseYear
genre: $genre
rating: $rating
})
}
query getMovieByKey($key: Movie_Key!) {
movie(key: $key) { id title }
}
query listMoviesByGenre($genre: String!) {
movies(where: {genre: {eq: $genre}}) {
id
title
}
}
then you could create and retrieve a movie as follows:
val connector = MoviesConnector.instance
val addMovieResult1 = connector.createMovie.execute(
title = "Empire Strikes Back",
releaseYear = 1980,
genre = "Sci-Fi",
rating = 5
)
val movie1 = connector.getMovieByKey.execute(addMovieResult1.data.key)
println("Empire Strikes Back: ${movie1.data.movie}")
You can also retrieve multiple movies:
val connector = MoviesConnector.instance
val addMovieResult2 = connector.createMovie.execute(
title="Attack of the Clones",
releaseYear = 2002,
genre = "Sci-Fi",
rating = 5
)
val listMoviesResult = connector.listMoviesByGenre.execute(genre = "Sci-Fi")
println(listMoviesResult.data.movies)
You can also collect a Flow that will only produce a result when a new query
result is retrieved using a call to the query's execute() method.
val connector = MoviesConnector.instance
connector.listMoviesByGenre.flow(genre = "Sci-Fi").collect { data ->
println(data.movies)
}
connector.createMovie.execute(
title="A New Hope",
releaseYear = 1977,
genre = "Sci-Fi",
rating = 5
)
connector.listMoviesByGenre.execute(genre = "Sci-Fi") // will cause the Flow to get notified
See Get realtime updates from SQL Connect.
An app's schema can contain enumerations, which can be accessed by your GraphQL queries.
As an app's design changes, you may add new enum supported values. For example,
imagine that later in your application’s lifecycle you decide to add a
FULLSCREEN value to the AspectRatio enum.
In the SQL Connect workflow, you can use local development tooling to update your queries and SDKs.
However, before you release an updated version of your clients, older deployed clients may break.
The generated SDK forces handling of unknown values as the customer's code must
unwrap the EnumValue object, which is either EnumValue.Known for known enum
values or EnumValue.Unknown for unknown values.
val result = connector.listMoviesByAspectRatio.execute(AspectRatio.WIDESCREEN)
val encounteredAspectRatios = mutableSetOf<String>()
result.data.movies
.mapNotNull { it.otherAspectRatios }
.forEach { otherAspectRatios ->
otherAspectRatios
.filterNot { it.value == AspectRatio.WIDESCREEN }
.forEach {
when (it) {
is EnumValue.Known -> encounteredAspectRatios.add(it.value.name)
is EnumValue.Unknown ->
encounteredAspectRatios.add("[unknown ratio: ${it.stringValue}]")
}
}
}
println(
"Widescreen movies also include additional aspect ratios: " +
encounteredAspectRatios.sorted().joinToString()
)
SQL Connect has an optional client-side caching feature, which you
can enable by editing the connector.yaml file. When this feature is enabled,
the generated client SDKs will locally cache query responses, which can reduce
the number of database requests your app makes and enables the
database-dependent portions of your app to work when network availability is
interrupted.
To enable client-side caching, add a client caching configuration to your connector configuration:
generate:
kotlinSdk:
outputDir: "../android"
package: "com.google.firebase.dataconnect.generated"
clientCache:
maxAge: 5s
storage: persistent
This configuration has two parameters, both optional:
maxAge: The maximum age a cached response can be before the client SDK
fetches fresh values. Examples: "0", "30s", "1h30m".
The default value for maxAge is 0, which means that responses are cached,
but the client SDK will always fetch fresh values. The cached values will only
be used when CACHE_ONLY is specified to execute().
storage: The client SDK can be configured to cache responses either in
persistent storage or in memory. Results cached in persistent storage
will persist across app restarts. In Android SDKs, the default is persistent.
After you update your connector's caching configuration, regenerate your client
SDKs and rebuild your app. Once you have done so, execute()
will cache
responses and use cached values according to the policy you configured. This
generally happens automatically, without any additional steps on your part;
however, note the following:
The default behavior of execute() is as described above: if a
result is cached for a query and the cached value is not older than maxAge,
then use the cached value. This default behavior is called the PREFER_CACHE
policy.
You can also specify to individual invocations of execute() to
either only serve cached values (CACHE_ONLY) or to unconditionally fetch
fresh values from the server (SERVER_ONLY).
val queryResult = queryRef.execute(QueryRef.FetchPolicy.CACHE_ONLY)
val queryResult = queryRef.execute(QueryRef.FetchPolicy.SERVER_ONLY)
You can use the SQL Connect emulator, whether from the SQL Connect VS Code extension or from the CLI.
Instrumenting the app to connect to the emulator is the same for both scenarios.
val connector = MoviesConnector.instance
// Connect to the emulator on "10.0.2.2:9399"
connector.dataConnect.useEmulator()
// (alternatively) if you're running your emulator on non-default port:
connector.dataConnect.useEmulator(port = 9999)
// Make calls from your app
To switch to production resources, comment out lines for connecting to the emulator.
The SQL Connect server represents common and custom GraphQL data types. These are represented in the SDK as follows.
| SQL Connect Type | Kotlin |
|---|---|
| String | String |
| Int | Int (32-bit integer) |
| Float | Double (64-bit float) |
| Boolean | Boolean |
| UUID | java.util.UUID |
| Date | com.google.firebase.dataconnect.LocalDate (was java.util.Date until 16.0.0-beta03) |
| Timestamp | com.google.firebase.Timestamp |
| Int64 | Long |
| Any | com.google.firebase.dataconnect.AnyValue |
Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see the Google Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2026-06-12 UTC.