diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 6d109a60e..ebb9d9b3e 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -47,7 +47,7 @@ jobs:
       - name: Build
         run: ./tools/build.sh
       - name: 'Upload Artifact'
-        uses: actions/upload-artifact@v3
+        uses: actions/upload-artifact@v4
         with:
           name: angularfire-${{ github.run_id }}
           path: dist
@@ -82,7 +82,7 @@ jobs:
         if: steps.node_modules_cache.outputs.cache-hit != 'true'
         run: npm ci
       - name: Download Artifacts
-        uses: actions/download-artifact@v3
+        uses: actions/download-artifact@v4
       - name: Relocate Artifacts
         run: mv angularfire-${{ github.run_id }} dist
       - name: Test Node
@@ -133,7 +133,7 @@ jobs:
           path: ~/.cache/firebase/emulators
           key: firebase_emulators
       - name: Download Artifacts
-        uses: actions/download-artifact@v3
+        uses: actions/download-artifact@v4
       - name: Relocate Artifacts
         run: mv angularfire-${{ github.run_id }} dist
       - name: Test browser
@@ -210,7 +210,7 @@ jobs:
           registry-url: 'https://registry.npmjs.org'
           check-latest: false
       - name: 'Download Artifacts'
-        uses: actions/download-artifact@v3
+        uses: actions/download-artifact@v4
       - name: Publish
         run: |
           cd ./angularfire-${{ github.run_id }}/packages-dist
diff --git a/package-lock.json b/package-lock.json
index eb7345108..0fe303560 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -80,7 +80,8 @@
         "ts-patch": "^3.2.1",
         "ts-transformer-keys": "^0.4.4",
         "tslint": "~6.1.0",
-        "typescript": ">=5.5 <5.7"
+        "typescript": ">=5.5 <5.7",
+        "yaml": "^2.7.0"
       }
     },
     "node_modules/@aashutoshrathi/word-wrap": {
@@ -10112,6 +10113,14 @@
         "node": ">=10"
       }
     },
+    "node_modules/cosmiconfig/node_modules/yaml": {
+      "version": "1.10.2",
+      "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+      "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
     "node_modules/cross-spawn": {
       "version": "7.0.3",
       "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -22521,11 +22530,15 @@
       "license": "ISC"
     },
     "node_modules/yaml": {
-      "version": "1.10.2",
-      "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
-      "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz",
+      "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==",
+      "dev": true,
+      "bin": {
+        "yaml": "bin.mjs"
+      },
       "engines": {
-        "node": ">= 6"
+        "node": ">= 14"
       }
     },
     "node_modules/yargs": {
diff --git a/package.json b/package.json
index c1b65f784..20357e87b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@angular/fire",
-  "version": "19.0.0",
+  "version": "19.1.0",
   "description": "Angular + Firebase = ❤️",
   "private": true,
   "scripts": {
@@ -12,6 +12,7 @@
     "test:chrome-headless": "npx --yes firebase-tools@latest emulators:exec --project=demo-123 \"ng test --watch=false --browsers=ChromeHeadless\"",
     "test:firefox-headless": "npx --yes firebase-tools@latest emulators:exec --project=demo-123 \"ng test --watch=false --browsers=FirefoxHeadless\"",
     "lint": "ng lint",
+    "lint:fix": "ng lint --fix",
     "test:node": "node -r tsconfig-paths/register ./dist/out-tsc/jasmine/tools/jasmine.mjs --input-type=commonjs",
     "test:node-esm": "node -r tsconfig-paths/register ./dist/out-tsc/jasmine/tools/jasmine.mjs",
     "test:typings": "node ./tools/run-typings-test.js",
@@ -116,7 +117,8 @@
     "ts-patch": "^3.2.1",
     "ts-transformer-keys": "^0.4.4",
     "tslint": "~6.1.0",
-    "typescript": ">=5.5 <5.7"
+    "typescript": ">=5.5 <5.7",
+    "yaml": "^2.7.0"
   },
   "typings": "index.d.ts"
 }
diff --git a/src/schematics/deploy/actions.jasmine.ts b/src/schematics/deploy/actions.jasmine.ts
index 890e76350..abae2e375 100644
--- a/src/schematics/deploy/actions.jasmine.ts
+++ b/src/schematics/deploy/actions.jasmine.ts
@@ -63,6 +63,9 @@ const initMocks = () => {
         create: () => Promise.reject(),
       }
     },
+    init() {
+      return Promise.resolve()
+    },
     deploy: (_: FirebaseDeployConfig) => Promise.resolve(),
     use: () => Promise.resolve(),
     logger: {
diff --git a/src/schematics/interfaces.ts b/src/schematics/interfaces.ts
index 916ac7725..a21df2168 100644
--- a/src/schematics/interfaces.ts
+++ b/src/schematics/interfaces.ts
@@ -21,7 +21,7 @@ export const featureOptions = [
   { name: 'App Check', value: FEATURES.AppCheck },
   { name: 'Firestore', value: FEATURES.Firestore },
   { name: 'Realtime Database', value: FEATURES.Database },
-  // { name: 'Data Connect', value: FEATURES.DataConnect },
+  { name: 'Data Connect', value: FEATURES.DataConnect },
   { name: 'Cloud Functions (callable)', value: FEATURES.Functions },
   { name: 'Cloud Messaging', value: FEATURES.Messaging },
   { name: 'Performance Monitoring', value: FEATURES.Performance },
@@ -132,6 +132,8 @@ export interface FirebaseTools {
   serve(options: any): Promise<any>;
 
   use(options: any, lol: any): Promise<any>;
+
+  init(feature: string, options: any): Promise<any>;
 }
 
 export interface FirebaseHostingRewrite {
@@ -149,9 +151,14 @@ export interface FirebaseHostingConfig {
 
 export type FirebaseFunctionsConfig = Record<string, any>;
 
+export interface DataConnectConfig {
+  source?: string;
+}
+
 export interface FirebaseJSON {
   hosting?: FirebaseHostingConfig[] | FirebaseHostingConfig;
   functions?: FirebaseFunctionsConfig;
+  dataconnect?: DataConnectConfig;
 }
 
 export interface FirebaseRcTarget {
@@ -225,3 +232,36 @@ export interface Workspace {
   defaultProject?: string;
   projects: Record<string, WorkspaceProject>;
 }
+
+export interface ConnectorConfig {
+  location: string;
+  connector: string;
+  service: string;
+}
+export interface ConnectorYaml {
+  connectorId: string;
+  generate?: {
+    javascriptSdk?: {
+      package: string;
+      outputDir: string;
+      packageJsonDir?: string;
+      angular?: boolean;
+    }
+  }
+}
+export interface DataConnectYaml {
+  location: string;
+  serviceId: string;
+  connectorDirs: string[];
+}
+export interface DataConnectConnectorConfig  {
+  connectorYaml: ConnectorYaml;
+  connectorConfig?: ConnectorConfig;
+  angular?: boolean;
+  package?: string;
+}
+
+export interface PackageJson {
+  dependencies: Record<string, string>;
+  devDependencies: Record<string, string>;
+}
diff --git a/src/schematics/setup/index.ts b/src/schematics/setup/index.ts
index fb26e8250..06e29f789 100644
--- a/src/schematics/setup/index.ts
+++ b/src/schematics/setup/index.ts
@@ -1,17 +1,20 @@
-import { writeFileSync } from 'fs';
+import { readFileSync, writeFileSync } from 'fs';
 import { join } from 'path';
 import { asWindowsPath, normalize } from '@angular-devkit/core';
 import { SchematicContext, Tree, chain } from '@angular-devkit/schematics';
 import { addRootProvider } from '@schematics/angular/utility';
 import { getFirebaseTools } from '../firebaseTools';
 import {
-  DeployOptions, FEATURES, FirebaseApp, FirebaseProject,
+  DataConnectConnectorConfig,
+  DeployOptions, FEATURES, FirebaseApp, FirebaseJSON, FirebaseProject,
 } from '../interfaces';
 import {
   addIgnoreFiles,
   featureToRules,
   getFirebaseProjectNameFromHost,
   getProject,
+  parseDataConnectConfig,
+  setupTanstackDependencies,
 } from '../utils';
 import { appPrompt, featuresPrompt, projectPrompt, userPrompt } from './prompts';
 
@@ -19,6 +22,9 @@ export interface SetupConfig extends DeployOptions {
   firebaseProject: FirebaseProject,
   firebaseApp?: FirebaseApp,
   sdkConfig?: Record<string, string>,
+  firebaseJsonConfig?: FirebaseJSON;
+  dataConnectConfig?: DataConnectConnectorConfig | null;
+  firebaseJsonPath: string;
 }
 
 export const setupProject =
@@ -35,7 +41,7 @@ export const setupProject =
             config.sdkConfig ? `{ ${Object.entries(config.sdkConfig).map(([k, v]) => `${k}: ${JSON.stringify(v)}`).join(", ")} }` : ""
           }))`;
         }),
-        ...featureToRules(features, projectName),
+        ...featureToRules(features, projectName, config.dataConnectConfig),
       ]);
     }
 };
@@ -56,6 +62,10 @@ export const ngAddSetupProject = (
 
     // Add the firebase files if they don't exist already so login.use works
     if (!host.exists('/firebase.json')) { writeFileSync(join(projectRoot, 'firebase.json'), '{}'); }
+    
+    let firebaseJson: FirebaseJSON = JSON.parse(
+      readFileSync(join(projectRoot, "firebase.json")).toString()
+    );
 
     const user = await userPrompt({ projectRoot });
     const defaultUser = await firebaseTools.login(options);
@@ -72,6 +82,11 @@ export const ngAddSetupProject = (
     let firebaseApp: FirebaseApp|undefined;
     let sdkConfig: Record<string, string>|undefined;
 
+    const setupConfig: SetupConfig = {
+      ...options, firebaseProject, firebaseApp, sdkConfig,
+      firebaseJsonConfig: firebaseJson,
+      firebaseJsonPath: projectRoot
+    };
     if (features.length) {
 
       firebaseApp = await appPrompt(firebaseProject, undefined, { projectRoot });
@@ -79,12 +94,45 @@ export const ngAddSetupProject = (
       const result = await firebaseTools.apps.sdkconfig('web', firebaseApp.appId, { nonInteractive: true, projectRoot });
       sdkConfig = result.sdkConfig;
       delete sdkConfig.locationId;
-
+      setupConfig.sdkConfig = sdkConfig;
+      setupConfig.firebaseApp = firebaseApp;
+      // set up data connect locally if data connect hasn't already been initialized.
+      if(features.includes(FEATURES.DataConnect)) {
+        if (!firebaseJson.dataconnect) {
+          try {
+            await firebaseTools.init("dataconnect", {
+              projectRoot,
+              project: firebaseProject.projectId,
+            });
+            // Update firebaseJson values to include newly added dataconnect field in firebase.json.
+            firebaseJson = JSON.parse(
+              readFileSync(join(projectRoot, "firebase.json")).toString()
+            );
+            setupConfig.firebaseJsonConfig = firebaseJson;
+          } catch (e) {
+            console.error(e);
+          }
+        }
+          let dataConnectConfig = parseDataConnectConfig(setupConfig);
+          if(!dataConnectConfig?.connectorYaml.generate?.javascriptSdk) {
+            await firebaseTools.init("dataconnect:sdk", {
+              projectRoot,
+              project: firebaseProject.projectId,
+            });
+          }
+          // Parse through sdk again
+          dataConnectConfig = parseDataConnectConfig(setupConfig);
+          if(dataConnectConfig?.angular) {
+            context.logger.info('Generated Angular SDK Enabled.');
+          } else {
+            context.logger.info('Generated Angular SDK Disabled. Please add `angular: true` to your connector.yaml');
+          }
+          setupTanstackDependencies(host, context);
+          setupConfig.dataConnectConfig = dataConnectConfig;
+        }
+      
     }
 
-    return setupProject(host, context, features, {
-      ...options, firebaseProject, firebaseApp, sdkConfig,
-    });
-
+    return setupProject(host, context, features, setupConfig);
   }
 };
diff --git a/src/schematics/utils.ts b/src/schematics/utils.ts
index 73fea996b..b42afb07c 100644
--- a/src/schematics/utils.ts
+++ b/src/schematics/utils.ts
@@ -1,16 +1,37 @@
-import { readFileSync } from 'fs';
-import { join } from 'path';
-import { Rule, SchematicsException, Tree, chain } from '@angular-devkit/schematics';
-import { addRootProvider } from '@schematics/angular/utility';
-import { overwriteIfExists } from './common';
-import { DeployOptions, FEATURES, FirebaseApp, FirebaseRc, Workspace } from './interfaces';
+import { readFileSync } from "fs";
+import { join } from "path";
+import {
+  Rule,
+  SchematicContext,
+  SchematicsException,
+  Tree,
+  chain,
+} from "@angular-devkit/schematics";
+import { NodePackageInstallTask } from "@angular-devkit/schematics/tasks";
+import { addRootProvider } from "@schematics/angular/utility";
+import { parse } from "yaml";
+import { overwriteIfExists, safeReadJSON, stringifyFormatted } from "./common";
+import {
+  ConnectorConfig,
+  ConnectorYaml,
+  DataConnectConnectorConfig,
+  DataConnectYaml,
+  DeployOptions,
+  FEATURES,
+  FirebaseApp,
+  FirebaseRc,
+  PackageJson,
+  Workspace,
+} from "./interfaces";
+import { SetupConfig } from "./setup";
 
-export const shortAppId = (app?: FirebaseApp) => app?.appId?.split('/').pop();
+export const shortAppId = (app?: FirebaseApp) => app?.appId?.split("/").pop();
 
-export function getWorkspace(
-  host: Tree
-): { path: string; workspace: Workspace } {
-  const path = '/angular.json';
+export function getWorkspace(host: Tree): {
+  path: string;
+  workspace: Workspace;
+} {
+  const path = "/angular.json";
 
   const configBuffer = path && host.read(path);
   if (!configBuffer) {
@@ -18,16 +39,16 @@ export function getWorkspace(
   }
 
   // eslint-disable-next-line @typescript-eslint/no-var-requires
-  const { parse } = require('jsonc-parser');
+  const { parse } = require("jsonc-parser");
 
-  const workspace = parse(configBuffer.toString()) as Workspace|undefined;
+  const workspace = parse(configBuffer.toString()) as Workspace | undefined;
   if (!workspace) {
-    throw new SchematicsException('Could not parse angular.json');
+    throw new SchematicsException("Could not parse angular.json");
   }
 
   return {
     path,
-    workspace
+    workspace,
   };
 }
 
@@ -37,31 +58,31 @@ export const getProject = (options: DeployOptions, host: Tree) => {
 
   if (!projectName) {
     throw new SchematicsException(
-      'No Angular project selected and no default project in the workspace'
+      "No Angular project selected and no default project in the workspace"
     );
   }
 
   const project = workspace.projects[projectName];
   if (!project) {
     throw new SchematicsException(
-      'The specified Angular project is not defined in this workspace'
+      "The specified Angular project is not defined in this workspace"
     );
   }
 
-  if (project.projectType !== 'application') {
+  if (project.projectType !== "application") {
     throw new SchematicsException(
       `Deploy requires an Angular project type of "application" in angular.json`
     );
   }
 
-  return {project, projectName};
+  return { project, projectName };
 };
 
 export function getFirebaseProjectNameFromHost(
   host: Tree,
   target: string
-): [string|undefined, string|undefined] {
-  const buffer = host.read('/.firebaserc');
+): [string | undefined, string | undefined] {
+  const buffer = host.read("/.firebaserc");
   if (!buffer) {
     return [undefined, undefined];
   }
@@ -72,8 +93,8 @@ export function getFirebaseProjectNameFromHost(
 export function getFirebaseProjectNameFromFs(
   root: string,
   target: string
-): [string|undefined, string|undefined] {
-  const path = join(root, '.firebaserc');
+): [string | undefined, string | undefined] {
+  const path = join(root, ".firebaserc");
   try {
     const buffer = readFileSync(path);
     const rc: FirebaseRc = JSON.parse(buffer.toString());
@@ -83,10 +104,13 @@ export function getFirebaseProjectNameFromFs(
   }
 }
 
-const projectFromRc = (rc: FirebaseRc, target: string): [string|undefined, string|undefined] => {
+const projectFromRc = (
+  rc: FirebaseRc,
+  target: string
+): [string | undefined, string | undefined] => {
   const defaultProject = rc.projects?.default;
   const project = Object.keys(rc.targets || {}).find(
-    project => !!rc.targets?.[project]?.hosting?.[target]
+    (project) => !!rc.targets?.[project]?.hosting?.[target]
   );
   const site = project && rc.targets?.[project]?.hosting?.[target]?.[0];
   return [project || defaultProject, site];
@@ -104,26 +128,43 @@ export function addFixesToServer(host: Tree) {
   if (text === null) {
     throw new SchematicsException(`File ${serverPath} does not exist.`);
   }
-  const sourceText = text.toString('utf-8');
-  const addZonePatch = !sourceText.includes('import \'zone.js/dist/zone-patch-rxjs\';');
+  const sourceText = text.toString("utf-8");
+  const addZonePatch = !sourceText.includes(
+    "import 'zone.js/dist/zone-patch-rxjs';"
+  );
 
   if (addZonePatch) {
-    overwriteIfExists(host, serverPath, sourceText.replace('import \'zone.js/dist/zone-node\';', `import 'zone.js/dist/zone-node';
-${addZonePatch ? 'import \'zone.js/dist/zone-patch-rxjs\';' : ''}`));
+    overwriteIfExists(
+      host,
+      serverPath,
+      sourceText.replace(
+        "import 'zone.js/dist/zone-node';",
+        `import 'zone.js/dist/zone-node';
+${addZonePatch ? "import 'zone.js/dist/zone-patch-rxjs';" : ""}`
+      )
+    );
   }
 
   return host;
 }
 
-export function featureToRules(features: FEATURES[], projectName: string) {
-  return features.map(feature => {
-    switch (feature) {
+export function featureToRules(
+  features: FEATURES[],
+  projectName: string,
+  dataConnectConfig?: DataConnectConnectorConfig | null
+) {
+  return features
+    .map((feature) => {
+      switch (feature) {
         case FEATURES.AppCheck:
           // TODO make this smarter in Angular Universal
-          return addRootProvider(projectName, ({code, external}) => {
-            external('initializeAppCheck', '@angular/fire/app-check');
-            external('ReCaptchaEnterpriseProvider', '@angular/fire/app-check');
-            return code`${external('provideAppCheck', '@angular/fire/app-check')}(() => {
+          return addRootProvider(projectName, ({ code, external }) => {
+            external("initializeAppCheck", "@angular/fire/app-check");
+            external("ReCaptchaEnterpriseProvider", "@angular/fire/app-check");
+            return code`${external(
+              "provideAppCheck",
+              "@angular/fire/app-check"
+            )}(() => {
   // TODO get a reCAPTCHA Enterprise here https://console.cloud.google.com/security/recaptcha?project=_
   const provider = new ReCaptchaEnterpriseProvider(/* reCAPTCHA Enterprise site key */);
   return initializeAppCheck(undefined, { provider, isTokenAutoRefreshEnabled: true });
@@ -131,83 +172,144 @@ export function featureToRules(features: FEATURES[], projectName: string) {
           });
         case FEATURES.Analytics:
           return chain([
-            addRootProvider(projectName, ({code, external}) => {
-              external('getAnalytics', '@angular/fire/analytics');
-              return code`${external('provideAnalytics', '@angular/fire/analytics')}(() => getAnalytics())`;
+            addRootProvider(projectName, ({ code, external }) => {
+              external("getAnalytics", "@angular/fire/analytics");
+              return code`${external(
+                "provideAnalytics",
+                "@angular/fire/analytics"
+              )}(() => getAnalytics())`;
             }),
             // TODO if using Angular router
-            addRootProvider(projectName, ({code, external}) => {
-              return code`${external('ScreenTrackingService', '@angular/fire/analytics')}`;
+            addRootProvider(projectName, ({ code, external }) => {
+              return code`${external(
+                "ScreenTrackingService",
+                "@angular/fire/analytics"
+              )}`;
             }),
-            ...(features.includes(FEATURES.Authentication) ? [
-              addRootProvider(projectName, ({code, external}) => {
-                return code`${external('UserTrackingService', '@angular/fire/analytics')}`;
-              })
-            ] : []),
-          ])
+            ...(features.includes(FEATURES.Authentication)
+              ? [
+                  addRootProvider(projectName, ({ code, external }) => {
+                    return code`${external(
+                      "UserTrackingService",
+                      "@angular/fire/analytics"
+                    )}`;
+                  }),
+                ]
+              : []),
+          ]);
         case FEATURES.Authentication:
-          return addRootProvider(projectName, ({code, external}) => {
-            external('getAuth', '@angular/fire/auth');
-            return code`${external('provideAuth', '@angular/fire/auth')}(() => getAuth())`;
+          return addRootProvider(projectName, ({ code, external }) => {
+            external("getAuth", "@angular/fire/auth");
+            return code`${external(
+              "provideAuth",
+              "@angular/fire/auth"
+            )}(() => getAuth())`;
           });
         case FEATURES.Database:
-          return addRootProvider(projectName, ({code, external}) => {
-            external('getDatabase', '@angular/fire/database');
-            return code`${external('provideDatabase', '@angular/fire/database')}(() => getDatabase())`;
+          return addRootProvider(projectName, ({ code, external }) => {
+            external("getDatabase", "@angular/fire/database");
+            return code`${external(
+              "provideDatabase",
+              "@angular/fire/database"
+            )}(() => getDatabase())`;
           });
         case FEATURES.DataConnect:
-          throw "unimplemented.";
-        //  TODO need to add the generation of the project, grab the connector config
-        //  that requires this go async
-        //  return addRootProvider(projectName, ({code, external}) => {
-        //    external('getDataConnect', '@angular/fire/data-connect');
-        //    return code`${external('provideDataConnect', '@angular/fire/data-connect')}(() => getDataConnect())`;
-        //  });
+          return addRootProvider(projectName, ({ code, external }) => {
+            external("getDataConnect", "@angular/fire/data-connect");
+            let configAsStr = "{}";
+
+            const config = dataConnectConfig;
+            let angularConfig: undefined | string;
+            if (config) {
+              if (config.package) {
+                configAsStr = external("connectorConfig", config.package);
+              } else {
+                configAsStr = `{${Object.keys(config.connectorConfig as ConnectorConfig).map(
+                  (key) => `${key}: "${(config.connectorConfig as ConnectorConfig)[key]}"`
+                ).join(',')}}`;
+              }
+              if (config.angular) {
+                angularConfig = `, ${external(
+                  "provideTanStackQuery",
+                  "@tanstack/angular-query-experimental"
+                )}(new ${external(
+                  "QueryClient",
+                  "@tanstack/angular-query-experimental"
+                )}())`;
+              }
+            }
+            return code`${external(
+              "provideDataConnect",
+              "@angular/fire/data-connect"
+            )}(() => getDataConnect(${configAsStr}))${angularConfig ?? ""}`;
+          });
         case FEATURES.Firestore:
-          return addRootProvider(projectName, ({code, external}) => {
-            external('getFirestore', '@angular/fire/firestore');
-            return code`${external('provideFirestore', '@angular/fire/firestore')}(() => getFirestore())`;
+          return addRootProvider(projectName, ({ code, external }) => {
+            external("getFirestore", "@angular/fire/firestore");
+            return code`${external(
+              "provideFirestore",
+              "@angular/fire/firestore"
+            )}(() => getFirestore())`;
           });
         case FEATURES.Functions:
-          return addRootProvider(projectName, ({code, external}) => {
-            external('getFunctions', '@angular/fire/functions');
-            return code`${external('provideFunctions', '@angular/fire/functions')}(() => getFunctions())`;
+          return addRootProvider(projectName, ({ code, external }) => {
+            external("getFunctions", "@angular/fire/functions");
+            return code`${external(
+              "provideFunctions",
+              "@angular/fire/functions"
+            )}(() => getFunctions())`;
           });
         case FEATURES.Messaging:
           // TODO add the service worker
-          return addRootProvider(projectName, ({code, external}) => {
-            external('getMessaging', '@angular/fire/messaging');
-            return code`${external('provideMessaging', '@angular/fire/messaging')}(() => getMessaging())`;
+          return addRootProvider(projectName, ({ code, external }) => {
+            external("getMessaging", "@angular/fire/messaging");
+            return code`${external(
+              "provideMessaging",
+              "@angular/fire/messaging"
+            )}(() => getMessaging())`;
           });
         case FEATURES.Performance:
-          return addRootProvider(projectName, ({code, external}) => {
-            external('getPerformance', '@angular/fire/performance');
-            return code`${external('providePerformance', '@angular/fire/performance')}(() => getPerformance())`;
+          return addRootProvider(projectName, ({ code, external }) => {
+            external("getPerformance", "@angular/fire/performance");
+            return code`${external(
+              "providePerformance",
+              "@angular/fire/performance"
+            )}(() => getPerformance())`;
           });
         case FEATURES.Storage:
-          return addRootProvider(projectName, ({code, external}) => {
-            external('getStorage', '@angular/fire/storage');
-            return code`${external('provideStorage', '@angular/fire/storage')}(() => getStorage())`;
+          return addRootProvider(projectName, ({ code, external }) => {
+            external("getStorage", "@angular/fire/storage");
+            return code`${external(
+              "provideStorage",
+              "@angular/fire/storage"
+            )}(() => getStorage())`;
           });
         case FEATURES.RemoteConfig:
           // TODO consider downloading the defaults
-          return addRootProvider(projectName, ({code, external}) => {
-            external('getRemoteConfig', '@angular/fire/remote-config');
-            return code`${external('provideRemoteConfig', '@angular/fire/remote-config')}(() => getRemoteConfig())`;
+          return addRootProvider(projectName, ({ code, external }) => {
+            external("getRemoteConfig", "@angular/fire/remote-config");
+            return code`${external(
+              "provideRemoteConfig",
+              "@angular/fire/remote-config"
+            )}(() => getRemoteConfig())`;
           });
         case FEATURES.VertexAI:
-          return addRootProvider(projectName, ({code, external}) => {
-            external('getVertexAI', '@angular/fire/vertexai');
-            return code`${external('provideVertexAI', '@angular/fire/vertexai')}(() => getVertexAI())`;
+          return addRootProvider(projectName, ({ code, external }) => {
+            external("getVertexAI", "@angular/fire/vertexai");
+            return code`${external(
+              "provideVertexAI",
+              "@angular/fire/vertexai"
+            )}(() => getVertexAI())`;
           });
         default:
           return undefined;
       }
-  }).filter((it): it is Rule => !!it);
+    })
+    .filter((it): it is Rule => !!it);
 }
 
 export const addIgnoreFiles = (host: Tree) => {
-  const path = '/.gitignore';
+  const path = "/.gitignore";
   if (!host.exists(path)) {
     return host;
   }
@@ -218,14 +320,81 @@ export const addIgnoreFiles = (host: Tree) => {
   }
 
   const content = buffer.toString();
-  if (!content.includes('# Firebase')) {
-    overwriteIfExists(host, path, content.concat(`
+  if (!content.includes("# Firebase")) {
+    overwriteIfExists(
+      host,
+      path,
+      content.concat(`
 # Firebase
 .firebase
 *-debug.log
 .runtimeconfig.json
-`));
+`)
+    );
   }
 
   return host;
 };
+
+export function parseDataConnectConfig(
+  config: SetupConfig
+): DataConnectConnectorConfig | null {
+  if (!config.firebaseJsonConfig) {
+    throw new Error("No firebase json");
+  }
+  if (!config.firebaseJsonConfig.dataconnect?.source) {
+    throw new Error(
+      "Couldn't find data connect configuration. Running `firebase init dataconnect`"
+    );
+  }
+  const dataConnectFolder = join(
+    config.firebaseJsonPath,
+    config.firebaseJsonConfig.dataconnect?.source
+  );
+  const sourcePath = join(dataConnectFolder, "dataconnect.yaml");
+  try {
+    const fileAsStr = readFileSync(sourcePath).toString();
+    const dataConnectYaml: DataConnectYaml = parse(fileAsStr);
+    const connectorPath = join(
+      dataConnectFolder,
+      dataConnectYaml.connectorDirs[0],
+      "connector.yaml"
+    );
+    const connectorAsStr = readFileSync(connectorPath).toString();
+    const connectorJson: ConnectorYaml = parse(connectorAsStr);
+    if (!connectorJson?.generate?.javascriptSdk) {
+      return { connectorYaml: connectorJson };
+    }
+    return {
+      connectorYaml: connectorJson,
+      connectorConfig: {
+        connector: connectorJson.connectorId,
+        location: dataConnectYaml.location,
+        service: dataConnectYaml.serviceId,
+      },
+      package: connectorJson.generate.javascriptSdk.package,
+      angular: connectorJson.generate.javascriptSdk.angular,
+    };
+  } catch (e) {
+    console.error("Couldn't parse dataconnect.yaml", e);
+    return null;
+  }
+}
+
+export function setupTanstackDependencies(
+  host: Tree,
+  context: SchematicContext
+) {
+  const packageJson: PackageJson = safeReadJSON("package.json", host);
+  const tanstackFirebasePackage = "@tanstack-query-firebase/angular";
+  if (
+    !packageJson.dependencies[tanstackFirebasePackage] &&
+    !packageJson.devDependencies[tanstackFirebasePackage]
+  ) {
+    packageJson.dependencies[tanstackFirebasePackage] =
+      "^1.0.0";
+    packageJson.dependencies["@tanstack/angular-query-experimental"] = "5.66.4";
+    overwriteIfExists(host, "package.json", stringifyFormatted(packageJson));
+    context.addTask(new NodePackageInstallTask());
+  }
+}
