Skip to content

feat(schematics): generate .firebaserc and Firestore starter files during ng add#3714

Merged
armando-navarro merged 4 commits into
angular:mainfrom
armando-navarro:feat/ng-add-firestore-scaffolding
Jul 16, 2026
Merged

feat(schematics): generate .firebaserc and Firestore starter files during ng add#3714
armando-navarro merged 4 commits into
angular:mainfrom
armando-navarro:feat/ng-add-firestore-scaffolding

Conversation

@armando-navarro

Copy link
Copy Markdown
Collaborator

Fixes #3713

ng add @angular/fire currently leaves the workspace un-deployable: the project selected during setup is recorded nowhere, firebase.json stays {} (#3559), and selecting Firestore produces no security rules. This PR makes the setup schematic generate the same starter files firebase init would:

  • .firebaserc — records the selected project as projects.default, merging into an existing file (other aliases and targets preserved). Written to the real filesystem after the firebaseTools.init calls, since init writes .firebaserc on disk during the same run.
  • firestore.rules — only when Firestore is selected and no rules file exists: the same test-mode starter template firebase init firestore uses (30-day expiry), with a warning logged at generation time. Never overwrites an existing rules file.
  • firestore.indexes.json — an empty manifest, so a plain firebase deploy doesn't fail on the referenced-but-missing file.
  • firebase.json gains the firestore section pointing at both files, written after the Data Connect initialization (which rewrites firebase.json on disk during the same run).

The rules and indexes files go through the schematic Tree (visible in the CREATE log, honored by --dry-run); .firebaserc and the firebase.json section are written to the real filesystem because firebase-tools reads and writes both during the same run.

Includes 14 specs (setup/firebaseConfigs.jasmine.ts); verified end-to-end against a real project (all four artifacts generated correctly; firebase use resolves without prompting).

Known limitations, not addressed here: the initial firebase.json '{}' write at the top of the flow (pre-existing) uses a raw writeFileSync and fires even under --dry-run; and because the firebase.json firestore section reaches disk before the Tree-staged rules/indexes files do, a failure late in the schematic can leave firebase.json referencing files that were never written. Moving firebase.json fully onto the Tree — the deeper fix for both — is a larger refactor.

…ring ng add

ng add asks the user to pick a Firebase project but never records the
choice, so every later firebase-tools command has no default project.
It also leaves firebase.json empty and creates no security rules, so a
Firestore-selected workspace cannot deploy rules at all.

Now, after the project prompt, the schematic records the selection in
.firebaserc (merging into an existing file rather than replacing it).
When Firestore is selected it also generates firestore.rules and
firestore.indexes.json — the same test-mode starter files that
'firebase init firestore' produces, with a warning that the rules
expire in 30 days — and wires the firestore section into firebase.json.
Existing rules files are left untouched.

The new files go through the schematic Tree; firebase.json stays on the
real filesystem because firebase-tools reads and rewrites it during the
same run, and its firestore section is added only after those rewrites.
* whose firebase.json already has a `firestore` section is left entirely untouched: its section
* may point at differently-named files, and creating the default-named ones would only add
* orphans nothing references.
*/

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth adding one sentence here noting that this must be called with the pre-init firebaseJson snapshot (not a post-init re-read). If a future firebaseTools.init call adds a firestore section to firebase.json on disk, addFirestoreToFirebaseJson will correctly skip, but the Tree-staged starter files will have already been created and will be orphaned. The ordering constraint is non-obvious without it.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch - traced it further and it's a bit worse than an orphan: if a future init call adds a firestore section while this is still reading the pre-init snapshot, it'd stage the default-named starter files right on top of the ones that init call would have written to disk - the same collision .firebaserc hit earlier in this PR, which aborts the whole ng add. So:

  • I moved the call to run after the init calls with a fresh re-read, rather than just documenting the risk.
  • Also worth noting: it now has to run before addFirestoreToFirebaseJson, since that's what actually adds the firestore section on a normal run — added a comment on that ordering too.

Comment thread src/schematics/setup/firebaseConfigs.ts Outdated
}
if (!firebaseJson.firestore) {
firebaseJson.firestore = { rules: 'firestore.rules', indexes: 'firestore.indexes.json' };
writeFileSync(join(projectRoot, 'firebase.json'), stringifyFormatted(firebaseJson));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The try/catch above only covers the readFileSync. If this writeFileSync fails (disk full, permissions), the error propagates as a raw Node error with no helpful message. A try/catch around the write with a context.logger.warn pointing the user to add the section manually would be consistent with how the read failure is handled above.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, and widened it a bit further - the try/catch now covers the read, the firestore property check/assignment, and the write together.

  • Found one more gap looking at it: a firebase.json that parses to null (valid JSON, not a usable object) was crashing on the property read one line above your comment, before it ever reached the write.
  • All three failure modes now get the same warn-and-continue instead of a raw error.

… handling

Tyler's review on angular#3714: createFirestoreStarterFiles staged the Tree
before the DataConnect init calls, using a pre-init firebase.json
snapshot. If a future init call ever added a firestore section
mid-run, the stale snapshot would miss it and stage starter files on
top of files firebase-tools already wrote to disk — the same
Tree/disk collision the .firebaserc write hit earlier in this PR.
Moved the call to run after init with a fresh re-read, and documented
the more immediate invariant this enforces: it must run before
addFirestoreToFirebaseJson, which is what adds the firestore section
on a normal run.

Also widened addFirestoreToFirebaseJson's try/catch to cover the
firebase.json mutation and write, not just the read — a write
failure (disk full, permissions) previously crashed with a raw Node
error instead of the warn-and-continue the read path already gets.
….json read fails

The re-read added for the firestore starter files was unguarded, so a
firebase.json that firebase-tools left unreadable would abort the whole
ng add. Before the starter files moved after the init calls, this same
failure degraded gracefully — the files were already staged, and
addFirestoreToFirebaseJson warned and let setup finish. Restore that:
warn and continue. createFirestoreStarterFiles independently checks the
disk for each file it would create, so a missing snapshot costs the
firestore-section check, not the collision safety it also relies on.

Trimmed the surrounding comments to the two constraints a future edit
could silently break — read after init, and run before
addFirestoreToFirebaseJson — and moved the rationale here.

The reason the read sits after the init calls at all: staging against a
stale pre-init snapshot risks the Tree/disk collision the .firebaserc
write hit earlier in this PR, where a Tree-staged file collides at
commit time with one firebase-tools already wrote to disk and aborts the
run. No init call adds a firestore section today, so that specific path
is defensive against a future one.
@armando-navarro armando-navarro merged commit 96cf855 into angular:main Jul 16, 2026
24 checks passed
@armando-navarro armando-navarro deleted the feat/ng-add-firestore-scaffolding branch July 16, 2026 02:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ng add never writes .firebaserc or Firestore starter files — deploys have no default project and no rules

2 participants