2022-03-08
3482
#nextjs
Doğacan Bilgili
31576
Mar 8, 2022 ⋅ 12 min read

Building a full-stack app with Next.js and Firebase’s Cloud Firestore

Doğacan Bilgili A software developer who is also into 3D-modeling and animation.

Recent posts:

Google & Shopify’s UCP: How AI agents sell online

Explore how the Universal Commerce Protocol (UCP) allows AI agents to connect with merchants, handle checkout sessions, and securely process payments in real-world e-commerce flows.

Emmanuel John
Feb 24, 2026 ⋅ 8 min read
6 React Server Component performance pitfalls in Next.js

6 React Server Component performance pitfalls in Next.js

React Server Components and the Next.js App Router enable streaming and smaller client bundles, but only when used correctly. This article explores six common mistakes that block streaming, bloat hydration, and create stale UI in production.

Temitope Oyedele
Feb 23, 2026 ⋅ 13 min read
podrocket 2 19

Making sense of web rendering patterns (SSR, CSR, static, islands)

Gil Fink (SparXis CEO) joins PodRocket to break down today’s most common web rendering patterns: SSR, CSR, static rednering, and islands/resumability.

PodRocket
Feb 23, 2026 ⋅ 48 sec read

CSS @container scroll-state: Replace JS scroll listeners now

CSS @container scroll-state lets you build sticky headers, snapping carousels, and scroll indicators without JavaScript. Here’s how to replace scroll listeners with clean, declarative state queries.

Jude Miracle
Feb 19, 2026 ⋅ 4 min read
View all posts

14 Replies to "Building a full-stack app with Next.js and Firebase’s Cloud Firestore"

  1. pages/api/entries.js should be something like this:
    import db from “../../utils/db”;

    export default async (req, res) => {
    try {
    const ref = db.collection(“entries”);
    const collections = await ref
    .orderBy(‘created’)
    .get();
    const entriesData = [];
    collections.forEach(doc => {
    entriesData.push({ …doc.data(), id: doc.id });
    })
    res.status(200).json({ entriesData });
    } catch (_) {
    res.status(400).end();
    }
    };

  2. I appreciate you taking the time to post this. It is never easy to put something out there. I just wanted to make you aware of some issues. I tried to follow this guide and ran into a lot of issues.
    – Right out of the gate the site wouldn’t load because having no argument in the catch caused a syntax error. I would recommend to anyone doing this at home to name the argument and console.log it to help with troubleshooting.
    – With that tweak, you can create a record by navigating to the admin/post page. However, since you are using `collection(‘entries’).add` in `api/entry/index.js` each new record is being assigned a document name of a random string. This breaks the selection code in `api/entry/[id].js` since it is selecting the document by the slug value. Changing that code in `api/entry/index.js` to `collection(‘entries’).doc(slug).set`solves that issue.
    – Your api/entries.js file isn’t selecting all of the existing entries. In fact, it matches the [id].js so it is requiring an id, which the edit/index.js and posts.file is not providing. Seems like a copypasta issue.
    A couple of less important housekeeping items:
    – `db.collection(‘entries’)` is repeated a lot in your api files, I would recommend setting a collection const at the top of the file and reusing that below.
    – out of the box, for some reason, next cannot seem to find the favicon and also has a console warning stating that the static directory is being depreciated and to use the public directory. Moving everything from the static directory to public solves both issues.
    – When you get them working, the `admin/edit/index.js` and `posts/index.js` components are iterating over an array of posts/entries but have no key defined. The fragment shorthand, “, should not be used when iterating, since it doesn’t support keys. Since slug is unique in your app, it will work for the key. You just need import React and use the long “ version.

    I hope this all helps and thank you again for taking a first stab at this. Even though it didn’t work out of the box, it has been a fun challenge getting it to work.

  3. Hey Keith,
    Thanks for the feedback. There were a couple of broken code blocks due to c/p errors and these were causing the issues you’ve mentioned. Now the whole article is revised and a new version will be published soon.

  4. Nice little snippets! But it would be useful to have an overview what you are going to build/building, I assume it’s a blog admin interface. Then maybe a bit about the NextJS implementation. Do you use it client side or both client/server generated code?

  5. Hey my config doesn’t have a databaseURL entry. After a lot of googling I have no idea if that matters or not. Seems like the databaseURL matters more for realtime database vs firestore but I can’t confirm if that is true. I’m planning on using firestore though 😬

  6. You should not use an async callback inside useEffect because it can cause race conditions. Instead, create an aync function inside of useEffect.

  7. Did you even ran this code ?

    I think its a terrible idea to read each documents to see if the slug is unique, if your database grow up and have like 2000 documents in it, you will need to read 2000 documents just for writting ONE SINGLE DOCUMENT !
    It very dangerous to publish a tutorial were you, because some people will simple copy/paste the code, go in prod and get 2000$ of firestore fees.

    To check if a slug is unique, you can simply name your document with the slug. So you can just list all the document (in one single read) and with that you can read the documents id and check if the document id match with your slug.

    Here is my code to do that:

    pages/api/entry/index.js

    import dn from “../../../utils/db”;

    export default async (req,res) => {
    console.log(“executed”);
    try{
    const {slug} = req.body
    const posts = await db.collection(‘posts’).get();// change the name of the collection
    var exist = false;
    posts.forEach((post)=> {if(post.id == slug){exist = true}})// check if the slug exist

    if ( exist ){
    //console.log(“slug exist”);
    res.status(200);
    }else{
    const {id} = await db.collection(“posts”).doc(slug).set({// doc(slug) will name (set the id of the doc) with the slug
    …req.body,
    created: new Date().toISOString(),
    })
    res.status(200).json({id});
    }

    }catch(e){
    console.log(e);
    res.status(400).end();
    }
    }

  8. as good as this project sounds, not including a live demo or a snippet of what we’re looking to build is wrong.

  9. It looks to me like you are using service credentials to completely bypass user authentication, but Next.js API routes are publicly accessible. In a browser they are protected by CORS maybe, but the routes can still be called from a non-browser environment. So in other words, I think this example code has a huuuge vunerability.

Leave a Reply

Would you be interested in joining LogRocket's developer community?

Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.

Sign up now