Why We Chose Next.js Over Gatsby for Our Event Website
Note: I’ve generalized some details to protect confidentiality. The point here is to explain the technical and operational reasoning behind the decision, not to turn it into a framework war.
The Problem
This was not a typical marketing site.
It was an event website, which meant it had to handle a strange mix of needs at the same time: schedules, speaker profiles, sponsor content, registration-related flows, time-sensitive updates, and heavy traffic around predictable moments. Some parts were basically static content. Other parts changed constantly, especially as the event got closer. And some workflows depended enough on the event system that pretending this was “just a content site” would have been misleading.
When we inherited it, the platform was already showing strain. Builds were slower than the team wanted. The data flow was more brittle than it should have been. Small content changes felt heavier than they needed to. During active event periods, the content team might need a speaker update, a session correction, or a sponsor change reflected quickly, and the platform did not give much confidence in those moments.
We were really choosing between two models.
One leaned harder into the static-site approach. The other gave us more flexibility route by route.
That is what put Gatsby and Next.js on the table.
More specifically, the practical choice became this:
Gatsby + Contentful + Netlify
Next.js + Contentful + Netlify
At the CMS and hosting layers, we were not trying to reinvent much. Contentful was already the right fit for the editorial side, and Netlify was already a comfortable operational model for the team. The real decision was about the application framework in the middle, and whether we wanted to keep forcing an event platform through a build-time-first model.
Gatsby Was Not Wrong. It Was Just the Wrong Fit.
I want to be fair to Gatsby because this was not a case of “good framework versus bad framework.”
Gatsby is good at what it is built for. If you have a content-heavy site, predictable publishing patterns, and build times your team can live with, it can be a very good choice. The problem for us was that this event website was not operating under those conditions. Your framework always looks different once real delivery pressure hits.
Build-time started working against us
Event content does not behave like blog content.
Schedules move. Speaker details change. Sponsors want updates late. Messaging changes closer to the event than anybody wants to admit. During active periods, updates can happen often enough that full rebuilds stop feeling like normal CI/CD and start feeling like operational drag.
That was one of the first signs Gatsby was becoming the wrong fit here. We were dealing with multi-minute builds for content changes at exactly the time the team needed the site to be more responsive, not less. Even when the build technically worked, the process felt too heavy for the pace of change around the event.
The extra data layer was not buying us enough
On a simpler site, Gatsby’s GraphQL layer can feel elegant.
On this platform, it mostly felt like one more thing to maintain.
Our event data had a lot of relationships in it. Sessions connected to speakers. Speakers connected to companies. Sponsors had their own structures. Different content types changed on different timelines. At that point, adding another layer between Contentful and the UI was not simplifying much. It mostly meant more queries to maintain, more cognitive load, and another place where complexity could hide.
The runtime story mattered more than it first appeared
This ended up being one of the deciding factors.
The site was not just publishing content. It also depended on registration and attendee-related workflows tied to an external event platform. Once that is true, the lack of a built-in server-side runtime stops being an abstract architectural concern and becomes a practical problem.
You can solve that with separate services, functions, and deployment paths. Plenty of teams do. But for us, that would have meant more moving parts, more handoffs, and more places where ownership could get fuzzy. We were trying to simplify the platform, not spread it across more surfaces.
There was also a team reality here. It is one thing to say, “we’ll just keep this integration logic in separate functions.” It is another thing to maintain that cleanly during event season, when content changes are flying, registration behavior matters, and the team needs to understand quickly where a problem actually lives.
Analytics got messier than we wanted
This was not the headline reason, but it mattered.
For an event website, stakeholders care a lot about which session pages draw interest, which sponsor pages get traffic, and where users drop off. Once you lean harder into client-side navigation, it becomes easier for analytics accuracy to drift unless the tracking model is very deliberate.
That problem is solvable. I just did not want the team carrying that extra burden if we had a cleaner option.
Why Next.js Ended Up Being the Better Fit
What I liked about Next.js was not that it was “better” in the abstract. It was that it let us stop pretending every route on the site had the same needs.
That was the real advantage.
Some pages could be static. Some could revalidate. Some needed request-time logic. Some needed authenticated or runtime-aware behavior. Next.js let us model the platform honestly instead of forcing everything through one delivery pattern. That fit the actual shape of the website better.
Incremental Static Regeneration helped almost immediately
ISR was one of the clearest wins for us.
A lot of the site still benefited from static generation. Speaker pages, marketing pages, FAQs, and plenty of read-heavy content did not need to be rebuilt from scratch every time something changed. They just needed to be fresh enough, fast enough, and easy for the team to operate.
That is where ISR helped. It gave us a middle ground between fully static and fully dynamic. More importantly, it reduced one of the recurring frustrations the team had been living with: a small content update no longer felt like it triggered an oversized deployment event.
Keeping integration logic closer to the app mattered
The event platform depended on more than content. Registration-related workflows, sync behavior, attendee-facing state, and event operations all had to connect cleanly with the rest of the site.
What Next.js gave us was a more unified place to put that logic.
Instead of thinking in terms of one front-end app plus a growing pile of disconnected service surfaces, we were able to keep more of the operational logic closer to the application itself. That made the system easier to reason about, and it made ownership clearer for the team. The closer we got to the event, the more that mattered.
Server-side work fit the real user experience better
There were places on the site where fresher checks mattered.
In those cases, I did not want the page to render first and then sort itself out in the browser after a chain of client-side requests. I wanted the user to land on something that already reflected the right state as much as possible.
That was another place where Next.js felt more natural. We could handle server-side work where it made sense, keep sensitive logic off the client, and reduce the amount of awkward loading-state choreography on pages that needed fresher data.
We were able to be more disciplined about JavaScript
A large percentage of the site was read-heavy content: schedules, speaker pages, venue information, FAQs, and similar pages that did not need a heavy client-side experience.
That pushed us toward a simpler question: how much JavaScript does this page actually need?
Next.js made it easier to be stricter about that. And on a site people may be loading from conference Wi-Fi, hotel networks, or overloaded venue connectivity, that matters more than architecture debates sometimes admit.
Request-time logic stopped feeling like a workaround
We also had cases where request-time decisions mattered, like gated experiences, redirect behavior, and route logic that did not fit neatly into a pure static model.
I liked having a framework that could deal with those needs directly instead of treating them like edge cases that had to be pushed into surrounding infrastructure.
What Was Harder Than Expected
No migration like this is clean.
One thing we underestimated was the mindset shift for the team. Gatsby encourages a certain way of thinking: shape the data at build time, generate the site, and keep the runtime story light. Next.js gives you more choices, which is useful, but it also means teams can get inconsistent fast if they do not agree on when to use static generation, revalidation, or request-time rendering.
We had to get more explicit about that than I would have liked. In hindsight, I would document route strategy earlier and make it part of code review sooner.
We also found that when a framework makes dynamic behavior easier, teams can overuse it at first. We had to push ourselves back toward discipline and ask a more boring but healthier question: does this route really need runtime work, or are we just taking the dynamic option because it is available?
And on the integration side, the migration reinforced something I have seen more than once: you do not fully know your edge cases until you start pulling the old system apart. There were behaviors that had quietly become part of production reality even if they were not especially well documented. That is normal, but it is still painful in the middle of a migration.
What Actually Mattered in the End
I would avoid pretending every migration produces a neat scoreboard that proves the decision scientifically.
What mattered most to us was more practical than that.
Content updates became less painful operationally. The platform was easier to reason about. The team had fewer disconnected pieces to keep in sync. The development model made more sense for a site that had both content-heavy pages and runtime-heavy workflows. And over time, the decision felt easier to defend because the platform fit the shape of the problem better.
That does not mean everything became simple. It means the tradeoffs improved.
When Gatsby Still Makes Sense
I would still use Gatsby in the right situation.
If I had a documentation site, a mostly static marketing site, or a content-heavy property with manageable build times and a straightforward data model, Gatsby would still be a reasonable option. Its plugin model is useful, and for the right type of site it can be very productive.
This just was not that type of site.
The event website was not a static site that occasionally needed dynamic behavior. It was a dynamic platform that happened to serve a lot of static content.
That distinction mattered more than any framework comparison chart.