4004 stories
·
4 followers

Why has Shopify dropped React Native?

1 Comment

Before we start: given this article is about native mobile development, I want to offer my 2021 ebook, ‘Building Mobile Apps at Scale: 39 engineering challenges’, for free to all readers. (normally costs $20). The book remains relevant on the challenges to solve for large-scale mobile applications, and lists the technologies covered below in this article, Kotlin Multiplatform included.

Claim your free copy here

This offer is valid until Friday, 2 October. On checkout, simply select “The ebook: PDF & EPUB versions of the book.” No credit card required! Feel free to share the link with colleagues who build mobile apps, or work on them.

Recently, Shopify dropped the bombshell announcement that Native is now the future of mobile development at the e-commerce platform. This triggered a lot of reaction in the mobile development community, on the scale of the stir Shopify generated when it originally moved over to React Native six years ago.

But times have changed, and we all know the agent of change this time: AI agents! This latest generation of models has improved in coding capability to the extent that Shopify no longer is satisfied with React Native (RN), as it was only last year.

This article looks into what led here, why Shopify made the change, and also the broader mobile ecosystem. We cover:

  1. Why Shopify chose React Native in 2020. Android apps took too long to build, first and foremost, and it was nice to have consistent iOS and Android apps.

  2. Still happy five years later. Shopify moved all six apps over to RN and most things were going well, and the 2020 move was seen as a good move.

  3. Why ditch React Native now? AI is now very good at writing mobile code as well as backend code, while React Native adds abstractions that native does not. Shopify rewrote the Shop app to native in just 12 weeks(!!). Additional details from the Shopify mobile team.

  4. Haven’t we seen this back-and-forth before? Airbnb did something similar by adopting React Native in 2016 before moving back to native just two years later. The underlying reason was the same: performance.

  5. Going native since 2019. Moving to native used to take a long time, and Notion has been at it for seven years. When Notion finishes the process, a fair question will be whether a native editor actually slows down their web iteration speed, with or without AI.

  6. Kotlin Multiplatform (KMP) would like a word. KMP allows the writing of business logic in Kotlin and sharing it across iOS and Android while each platform stays native. It’s a technology that feels relevant, and could become more popular with AI.

  7. What’s next? It’s easier to write native iOS and Android apps than before, but that’s also true for React, Flutter, and KMP apps.

Let’s rewind to 2020, when Shopify decided to go all-in on React Native (RN). Back then, mobile was a very important channel for the platform, with seven out of 10 customers using it on mobile devices. As Head of Engineering, Farhan Thawar wrote at the time:

“Each quarter, the majority of buyers purchase on mobile (with 71% of our buyers purchasing on mobile in Q3 of last year [in 2019]). Black Friday and Cyber Monday (together, BFCM) are the busiest time of year for our merchants, and buying activity during those days is a bellwether. During this year’s BFCM, Shopify merchants saw another 3% increase in purchases on mobile, an average of 69% of sales.”

With mobile so important, it’s no surprise the company built native mobile applications for iOS and Android; after all, native mobile gives full control of a platform’s capabilities, integrations, and performance, so why bother with cross-platform technology?

It turns out one reason was the delay in launching native apps on Android, which Shopify struggled with, along with other companies.

During the pandemic at the start of the decade, the live conversations app Clubhouse was a massive hit after launching in March 2020. The app was iOS-only for the first 14 months as the team was unable to release an Android app. And at the end of the year, usage absolutely exploded:

  • December 2020: 600,000 global installs (downloads) (source)

  • January 2021: 3.5 million global installs (source)

  • February 2022: 8 million global installs (source)

Clubhouse app: voice chat blew up with Covid-19. Source: TechCrunch

Despite all that popularity, Clubhouse was unavailable on Android at the time!

It took 14 months to launch a beta version of Clubhouse on Android, and by the time it did in May 2021, the platform had passed its peak a few months earlier and usage numbers were by then trending down. It took until July 2021 to roll out the Android Clubhouse app globally – 16 months after the iOS version – by which time it was too late to catch the growth wave, and that spelt doom for the promising business.

How did this happen? There were a few main reasons:

  1. Android is more complex to build well for than iOS: more device types to support, and much older OS versions to support with different APIs.

  2. Getting good performance on low-end Android phones was hard.

  3. I also wonder if Clubhouse’s team was engineering for a scale that never materialized. Perhaps they tried to build the “perfect” app to launch globally, but missed the growth wave, meaning the app ended up “over-engineered” compared to a different version that could’ve been released sooner, in a more timely fashion that benefitted the business.

Building a native Android app from scratch – even with an existing iOS app as a blueprint – was a challenge during the 2010s and early 2020s. Clubhouse is an extreme case of a business which went wrong, partly due to a sluggish Android launch.

But customer habits could have played a part: at the time, most US startups prioritized iOS apps and features first because in the US, the most valuable users were increasingly found on iOS. Prioritizing iOS made business sense for companies with mainly US customers, but not for ones with a global footprint, where regions like Asia featured mainly Android smartphone users.

Shopify’s first positive experience with React Native was in 2018 with the Shop app (then called ‘Arrive’). The company summarized (emphasis mine):

“At the end of 2018, we decided to rewrite one of our most popular consumer apps, Arrive (which is now Shop app) in React Native. Arrive is no slouch; it’s a highly rated, high performing app that has millions of downloads on iOS. It was a good candidate because we didn’t have an Android version. Our efforts would help us reach all of the Android users who were clamoring for Arrive. It’s now React Native on both iOS and Android and shares 95% of the same code. We’ll do a deep dive into Arrive in a future blog post.

So far, this rewrite resulted in:

  • fewer crashes on iOS than our native iOS app

  • an Android version launched

  • a team composed of mobile + non-mobile developers.”

Moving over to React Native was one of the easiest ways to speed up the rollout of Android versions of new apps. In 2020, when Shopify announced the move, that was the stated intention:

“Our popular Shopify Ping app (now called Shopify Inbox) which has enabled hundreds of thousands of customer conversations is currently only iOS. In 2020, we’ll be building the Android version using React Native out of our San Francisco office and we’re hiring.”

Last year, Shopify declared it was satisfied with the move to RN in a recap article, ‘Five years of React Native’. The summary was quite the victory lap:

“To recap, we decided to switch to RN for three main reasons:

  • Write it once - Stop building the same features twice, once on iOS and once on Android

  • Talent portability - Enable devs to work fluently across iOS, Android, and Web

  • Ship more value - Spend more time delivering value to users instead of chasing feature parity

We’re happy to share that our transition has been quite successful:

  • Not having to build the same features twice has given us a step change in productivity

  • Engineers are able to work across web and mobile allowing teams to do more with the same number of people and unlocked new growth opportunities

  • Maintaining feature parity between iOS and Android has become a non-issue, freeing up capacity to ship a lot more value

  • Our apps are blazing fast (<500ms screen loads) and stable (>99.9% crash-free sessions)

  • We continue to leverage native wherever it is the best tool for the job, giving us the best of both worlds

Over the past 5 years, we have migrated all our apps to React Native. Instead of using a one-size-fits-all approach to do so, each team chose when and how to migrate their app. This allowed them to continue shipping features while also aligning with our strategy of leveraging RN.”

They weren’t kidding: in five years, six mobile apps were migrated to React Native:

App migrations to React Native

Shopify’s engineering team said they loved a lot about React Native. Mustafa explained:

  • “Speed. RN apps are fast. We’ve achieved sub-500ms (P75) screen loads in the Shopify app. We’ve achieved similar performance in all our apps. Just like native, you have to apply good patterns and techniques to eliminate performance bottlenecks.

  • Hot reloading. This was one of our biggest pain points with native. Given the size of our code bases, it took several minutes for even the most trivial changes to be compiled and run on an emulator/physical device. This wastes time and breaks developer flow. React Native’s hot reloading completely eliminates this problem.

  • TypeScript is awesome as the “shared” language for devs. TypeScript has become ubiquitous, and we’ve seen great success with developers transitioning between React web and React Native.”

There were also some new challenges:

  • Worse debugging: “Debugging in React Native is flaky and configuring it correctly in VS Code takes some work. iOS and Android on the other hand have powerful debugging capabilities that just work”

  • Native code and devs still important. You want native code for performance-intensive code, certain animations, long-running background jobs and specialist APIs (like home screen widgets).

  • More third-party libraries. “The React Native framework is not as comprehensive compared to Native, so you end up having to use more third-party libraries.”

But how quickly things can change in tech…

There was widespread surprise this month when Shopify announced that Native is now the future of mobile at Shopify, meaning that RN is suddenly history.

From Head of Mobile, Mustafa Ali (emphasis mine):

“In January 2025, I wrote that the future of React Native was bright and that Shopify planned to keep investing in it. That was true based on what we knew then. React Native was working well for us, and it remains an excellent framework. But since then, coding models have gotten dramatically better, and for our apps and our team, building the same feature in Swift and Kotlin no longer carries the cost it used to.

Native still means building and maintaining software on two platforms, that cost has not disappeared. What changed is that agents can now do enough of the implementation, translation, testing, and review work that it’s no longer the deciding factor it was in 2020.

React Native apps can be fast. Ours are. We are making this change because agents have reduced the advantages of sharing implementation, while the advantages of building for each platform remain. Native keeps us closer to platform capabilities and first-party tooling, with fewer framework and dependency layers between our code and the platform.”

Of course, there have always been pros and cons in choosing native over cross-platform. Pre-AI, this is how it looked:

Native vs React Native development, observed across these four dimensions

What’s changed is that AI coding agents are now much more capable at generating iOS and Android code.

There’s no doubt that fully native apps are well-built and always more efficient than those built on a cross-platform interpreter like React Native. Nonetheless, RN has come a long way to be much more performant – with one additional abstraction layer between RN code and native code – especially since the New Architecture of 2024, Let’s visualize how it works:

How React Native renders views on iOS and Android

React Native’s core philosophy is to minimize updates done on the UI using expensive rendering operations. So, RN maintains a React Host Tree of visual elements on a screen (think a “logical tree”) which transform into a Host View Tree, the representation on iOS and Android. React itself cleverly minimizes re-rendering operations, which saves on compute resources.

As mentioned above, a well-written native app naturally outperforms a React Native version. The easiest way to see why this is, is to sketch what happens with native apps rendering, compared to with React Native:

React Native vs native rendering

React Native can theoretically be more performant, in the unlikely event the Native version has a poorly written structure, or if UIKit / Jetpack Compose or any other native library is inefficient enough for this to happen! But native has many fewer abstraction layers.

One common question since Shopify moved to native is how come the Shop app had not moved over to the New Architecture to improve things like startup performance. I reached out to Head of Mobile, Mustafa Ali, about that. He told me:

“We actually moved other big Shopify apps to the New Architecture. Shopify and Point of Sale were both migrated, and I believe we were one of the first large teams outside Meta to do it.

We got some performance gains with this migration, but they were modest. App startup got about 10% faster on Android and 3% on iOS, and some complex screens actually got slower until we tuned them.”

The team has written in detail about the move to New Architecture. Nonetheless, being on native code provides a lot more opportunities to improve performance; after all, you can now control the complete rendering stack! Heck, you could also throw away the Apple-built system libraries like UIKit or ComposeKit and build more performant ones. Shopify doesn’t plan to go this far, but Head of Engineering, Farhan Thawar, told me they expect performance wins:

“I think we’re just at the beginning of how much better these native apps will be. I expect they will get faster – like with better startup time and more responsive interactivity – as we work through the codebase post migration.”

One benefit of React Native was that it wasn’t necessary to have both an iOS engineer and an Android engineer. But with AI, one engineer can build software on both platforms, Mustafa Ali told me:

“One cultural benefit of switching to RN in the past is that we don’t have a separate iOS and Android team, unlike most native shops.

We have one team, and the same developer builds a feature on both iOS and Android. This keeps the context in one place and there’s no communication overhead.

With LLMs making it easy to contribute code outside of your main expertise, I expect this to become more common in the coming months.”

Farhan put it even more simply:

“Basically, React, as the shared language, is now replaced by the English language, thanks to LLMs.”

Another downside of going native is having two codebases to maintain, which tend to diverge from each other in behavior, features, and bugs. But with AI, Shopify doesn’t see this as a big problem any more. Mustafa:

“Maintaining two separate codebases was a big deal before LLMs, but not anymore.

Agents are quite good at porting a feature from Android to iOS or the other way around. They are also good at comparing the two implementations over time. They can spot gaps in the code and in side-by-side testing, and fix them.”

Shopify is also building a shared verification test suite to validate the two apps as identical. Again, from Mustafa:

“We now have one shared test suite that validates business logic implemented in both Swift and Kotlin. This means that a feature can’t ship until it passes the exact same tests on both platforms. That logic runs headless on desktop, which gives agents a very fast feedback loop to iterate on.”

Smart! It also confirms my sense that verifying code is becoming very important for working with agents, as is building dedicated verification layers.

Let’s return to the comparison table and update it for how native + AI changes the equation for Shopify:

Native vs React Native development, with more capable AI agents

My personal sense is that the downsides of native development disappear with AI tools getting so good, and that Shopify now has full control over the performance and architecture of its native apps.

With the decision to go all-in on native with AI, the e-commerce business is committing to migrate all of its apps. With AI, it should be faster than the migration to React Native was. Mustafa, again:

“We are going to migrate all our mobile apps to Swift and Kotlin using AI throughout the process.

Shop has already shipped as a fully native app in just 12 weeks, the Shopify app is underway, and the rest will follow soon. We’re moving quickly, but not by lowering the bar.

Every rebuild must meet or exceed the performance, stability, accessibility, and product quality people expect today. This isn’t just the same apps rewritten in different languages. We’re rebuilding them so both humans and agents can understand, test, and change them quickly.”

Best of luck to the team with this migration! I’m looking forward to hearing about what they learn with this move.

Read the whole story
emrox
25 minutes ago
reply
I guess development time got down with AI, even when running agents in parallel to implement that feature on both platforms. On the other side, that time saved will now be spent on QA since every platform has it's quirks and it still needs to be confirmed everything works well on both. With RN I would trust it more when it's implemented it runs fine on both platforms
Hamburg, Germany
Share this story
Delete

Props Are Not a Design System

1 Share

Most UI kits let you pass any style as a prop — radius, size, color, or a wall of Tailwind classes, whatever you need. That flexibility is exactly the problem: it turns every component call into a one-off styling decision, and no two buttons end up the same. Let’s talk about practices that prevent building an inconsistent, unmaintainable code base that won’t scale.

The Red Circle (1970)

Look at this button built with Tailwind for example:

<button
  className="
    inline-flex items-center justify-center gap-2
    whitespace-nowrap rounded-md text-sm font-medium
    ring-offset-background transition-colors
    focus-visible:outline-none focus-visible:ring-2
    focus-visible:ring-ring focus-visible:ring-offset-2
    disabled:pointer-events-none disabled:opacity-50
    bg-primary text-primary-foreground
    hover:bg-primary/90
    h-10 px-4 py-2
    dark:bg-primary dark:text-primary-foreground
    dark:hover:bg-primary/90
    sm:h-9 sm:px-3
    md:h-10 md:px-4
    lg:text-base
    [&_svg]:pointer-events-none
    [&_svg]:size-4
    [&_svg]:shrink-0
  "
>
  Save changes
</button>

You can do the same thing with pure HTML too:

<button
  style="
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    white-space: nowrap;
    border-radius: 0.375rem;
    font-size: 0.875rem;
    line-height: 1.25rem;
    font-weight: 500;
    transition: color 150ms, background-color 150ms, border-color 150ms,
      text-decoration-color 150ms, fill 150ms, stroke 150ms;
    background-color: var(--primary);
    color: var(--primary-foreground);
    height: 2.5rem;
    padding: 0.5rem 1rem;
  "
>
  Save changes
</button>

Both examples do the same thing: the style is decided at the call site, instance by instance, instead of being named once and reused. That’s what I mean by inlining - the mechanism doesn’t matter, whether it’s a style attribute, style props, or a wall of utility classes.

Aside from the obvious technical issues of page size and caching, there are a few more important foundational problems:

  1. you cannot ensure visual consistency, even within a single file
  2. such code has no semantics, so you can’t tell what it means
  3. such code has no system behind it, so it is difficult to maintain - even with an LLM you’ll wait a long time, because this error-prone style requires many iterations to correct

To address these problems, we need to stop deciding style at the call site and start defining it once, as a reusable, named unit of the interface.

The implementation depends on the stack, but most projects today build on component-based UI kits, so that’s what the examples below will use. Each component will be built from variants and modifiers.

Use variants

A variant is the self-contained style that completely describes all the visual aspects of a component, given a semantic name.

You can use a variant like this:

<Button variant="primary">Save changes</Button>
<Button variant="secondary">Cancel</Button>

In pure HTML with BEM methodology, it would look like this:

<button class="Button Button__variant_primary">Save changes</button>
<button class="Button Button__variant_secondary">Cancel</button>

A variant must contain all implementation details of the visual - inner geometry, colors, typography, everything. It must not expect its styles to be supplemented by anything external, whether that’s a global reset, a stray font-family, or any other in-place styling.

A variant defines the semantic unit of the user interface. That’s what makes a design system observable: you can see exactly which variants of a component exist and consistently update all of them at once.

Use modifiers

When you use a UI kit on a large project with a rich visual design, you may be tempted to write something like this:

<Button
	variant="primary"
	radius="xl"
	fontSize="xl"
	fontWeight={500}
	fontFamily="fancy"
>
	Buy
</Button>

This is the same call-site styling problem again, just typed: the props override the variant from outside, so it no longer defines the button’s final look. Worse, those overrides don’t track the variant — update the variant or introduce a new color scheme, and they silently fall out of sync.

If we need a variation of a view, we can implement a modifier instead, to keep things manageable. A modifier is part of the component’s API, at the same level as the variant - not an escape hatch around it.

For example, we can use variant to set the visual style of a button and add a modifier size to control its geometry:

<Button variant="primary" size="xl">Buy</Button>

If we find ourselves applying many modifiers at once, that’s a signal to introduce another variant instead:

<Button variant="fancy-primary" size="xl">Buy</Button>

This is the core discipline: variants and modifiers aren’t just two features of a UI kit, they’re a rule for where a styling decision is allowed to live, and when a recurring combination of modifiers has earned its own name.

The implementation example in vanilla CSS with a BEM-style modifier:

.button__size_xl {
	border-radius: 12px;
	font-size: 3rem;
	font-weight: 500;
	/* ... */
}

CSS modules for Mantine UI:

.root {
	&[data-size="xl"] {
		border-radius: 12px;
		font-size: 3rem;
		font-weight: 500;
		/* ... */
	}
}

ChakraUI theme:

export default defineConfig({
	theme: {
		semanticTokens: {
			colors: {
				// ...
			},
		},
		recipes: {
			button: defineRecipe({
				variants: {
					size: {
						xl: {
							borderRadius: "12px",
							fontSize: "3rem",
							fontWeight: "500",
						},
					},
					variant: {
						accent: {
							// ...
						},
					},
				},
			}),
		},
	},
});

Same rule, three different technologies - variants and modifiers work regardless of the tools you use.

Design the system

This approach can be applied to almost any UI kit, even one that wasn’t designed with this discipline in mind.

If you follow it, you’ll eventually end up with a design system even if you didn’t set out to build one - you’ll naturally be forced to identify the reusable units of your interface. Your code will stop being a pile of one-off styling decisions and start being a system.

Read the whole story
emrox
18 hours ago
reply
Hamburg, Germany
Share this story
Delete

Next.js applications, powered by Vite: introducing Vinext 1.0 | Cloudflare Blog

1 Share

When we launched Vinext in February, it was the result of an audacious week-long AI-driven experiment to see how far one engineer, and a stack of tokens, could get to replicating the NextJS framework backed by Vite.

In the seven months since that experiment, Vinext has grown into a framework that our customers trust and run in production for high-traffic, dynamic applications.

Today we are announcing the release of Vinext 1.0, the latest step on our journey to make it possible to deploy Next.js apps anywhere. Vinext lets you take any Next.js application, whether it was built for the Pages or App Router, and make it portable to be deployed to any web platform, including the Cloudflare Workers free plan, Netlify, or AWS Lambda.

Vinext 1.0 brings with it sweeping improvements to compatibility, stability, and caching behaviors, and sets the project up for the long term. There’s never been a better time to take your Next.js project and convert it to Vinext; just run npx vinext check and npx vinext init.

Graduation to 1.0

On release Vinext was promising, but it was incomplete. Since then, we’ve spent a lot of time both improving App Router compatibility and expanding that to Pages Router apps — which we’ve learned many customers are longtime fans of, with large applications that are complex to migrate. We didn’t want Vinext to be a tool that only worked for people using the latest App Router features.

Our focus has been on adopting both these routers, and watching our test compatibility closely, which for most important customer-requested features now surpasses 99%.

Our test compatibility has risen to more than 99%, excluding cache components
Our test compatibility has risen to more than 99%, excluding cache components.

This improvement has been fueled through the community around our GitHub project. As soon as Vinext launched, that community threw it at a wide variety of applications to find the gaps. With their scrutiny, we found challenges not immediately obvious in the test coverage. Vinext needs to act exactly as Next.js behaves. It is not good enough to imitate functions with the same name. Building an alternative import { revalidatePath } is simple enough; the difficulty is in making sure it correctly affects the rendered pages, cache entry, and future requests.

Tracing requests through the application to make sure Vinext responds in the way expected — and replicating not just the API, but the behavior of this machine — was by far the more challenging aspect.

Once we’ve patched problems and brought new features forward, it’s important that we don’t regress, especially if Next.js makes a change. That’s why we’ve also built out our test suite: thousands of focused tests covering core framework behavior across both routers, the development and production server, and the deployment targets of Nodejs and Cloudflare Workers. We also run the Next.js end-to-end test suite against Vinext nightly, giving us a continually moving window on our compatibility, and making sure we immediately become aware of regressions coming from merged changes. Alongside the automated testing, we’ve been working directly with large customers that have Vinext in production to make sure they are not facing issues.

What’s in 1.0

The clearest messages we got from customers using Vinext is that certain Next.js features carry the framework and Vinext didn’t actually need to do everything that Next.js has launched in recent versions to be incredibly useful to them. So we focused on better support where you need it:

  • App Router, Pages Router, and Hybrid applications: We heard from customers that Pages Router was still important, and migrations are not a one-step process. Vinext therefore has support for both routing paths, including React Server Components, Server Actions, API routes, route handlers, middleware, and client-side navigation.
  • The complete page lifecycle: Pages can be rendered in many different ways: on the server, pre-rendered in the build, exported as static assets, or cached with page-level Incremental Static Regeneration (ISR). We’ve made sure that Background and on-demand revalidation work with any output.
  • Caching: Vinext has a shared set of caching functions across the App and Pages Router and the supported runtimes. We have further support for using Cloudflare’s Workers Cache.
  • Observability: Vinext provides Next.js-compatible tracing across both routers, so existing OpenTelemetry and Sentry setups continue to work. On Cloudflare Workers, traces also integrate with native Workers Observability.
  • Next.js ecosystem compatibility:  Vinext implements the public next/* surface and supports common Next patterns for use of authentication, MDX, image optimization, fonts, metadata, environment variables, and more.
  • First-class runtime support for Workers: While Vinext can run anywhere, server code can run in the Cloudflare workerd runtime during development and production, with direct access to bindings such as image optimization and hyperdrive. 

We’ve also made migration part of the framework: it takes two commands to verify that your Next.js install and any modification you have made is compatible, and set up the Vite and deployment configuration while keeping all your previous Next.js project structure.

When we talked to teams about what features were important for them, something stood out. Next.js 16 took a stance that Cache Components were an important part of the future of the framework, and yet most teams that we talked to were not using them and did not consider support a prerequisite to move. Therefore, Vinext today has limited support for the “use cache” directive that drives Cache Components, and though we will continue to improve compatibility there, we’re much more focused on the core priorities above.

Pre-rendering and cache warming

When we first announced Vinext, it supported Incremental Static Regeneration (ISR) after the first request, but it did not yet render pages during the build. Applications use generateStaticParams() and getStaticPaths() to identify pages that should be rendered when building, and they expect page-level ISR to connect those initial responses to background and on-demand revalidation.

Vinext 1.0 supports that lifecycle for both routers. It can prerender App Router and Pages Router routes during the build, serve those responses through page-level ISR, and invalidate them by path or tag. It also supports output: "export" when the result you want is a fully static site.

But this led us to question something: Why should this rendering happen during the build at all?

A site with tens or hundreds of thousands of possible URLs can spend a seriously long time rendering pages that receive little traffic. The build process cannot evaluate the long tail of traffic that most sites experience and therefore cannot focus compute time on the smaller number of more critical pages. Instead you waste hours of time waiting for sequential builds working their way through thousands of pages, long after the most important routes are done.

Cache warming is our solution to this, moving page prerendering from the build machine to Cloudflare’s network. Developers can continue to use Next.js primitives to identify the pages for prerendering, and Vinext can additionally identify high-traffic pages to add to this list. This happens in the background before your site is deployed to production, so that the moment it is, it is ready to serve rapid responses from the Cloudflare cache.

Inside the deployment process, this works by uploading a new Worker version and deploying it to 0% of production traffic, before then requesting pages specifically from that version. This allows the rendering pipeline to work before any real users hit the new deployment. Once the caches have been populated, the deployment can be promoted safely.

What we’re doing next

If the original experiment invented the one-off slopfork, the more consequential part has been how we can keep that process of self-improvement running indefinitely.

The project is now focused on keeping the framework up to date with everything happening upstream. Next.js canary receives new commits every day. Each morning, an agent reviews the changes, fetches diffs, and opens tracking issues for anything that could affect Vinext. Every night, the compatibility matrix is regenerated as we run the Next.js test suite against Vinext.

When one of these tests or issues reveals a gap, agents are now in the position where they can identify the change across both codebases, build a reproduction, port any relevant tests, and propose a fix.

This review has been catching missing cases, unsafe caching behaviors, and differences in the development vs. production servers.

Automation has helped us narrow the stream of activity into a focused set of changes that deserve attention, allowing the maintainers of the project to focus on only the issues that need context of how a process should map onto Vite from the Next.js implementation.

We’re building a software factory for open source at Cloudflare, and you can see what we’re up to on GitHub.

Try it out

Vinext is available for new applications, and existing Next.js projects.

Start a new application today:

npm create vinext-app@latest my-app

Or migrate an existing application:

npx vinext check && npx vinext init

And then deploy it to Cloudflare Workers, with our cache warming:

npx @vinext/cloudflare deploy --warm-cache

Visit vinext.dev for documentation, examples, and the current compatibility matrix. Vinext is open source at github.com/cloudflare/vinext. Issues, pull requests, application reproductions, and feedback are welcome.

Read the whole story
emrox
18 hours ago
reply
Hamburg, Germany
Share this story
Delete

You should never be angry at work

1 Share

I try not to give a lot of prescriptive advice about working in tech companies1. There are many ways to be successful, and every company works differently. If you’re shipping projects and your management chain is happy, it doesn’t really matter how you’ve accomplished it. However, there’s one thing that I do think is solid advice: you should never be angry at work.

Anger in the workplace

Anger in the workplace is toxic. An angry colleague immediately becomes a new problem to be managed, not a professional helping you manage problems. When someone is visibly angry in a meeting or in Slack, it kills the entire atmosphere: other engineers will often go quiet entirely, not wanting to make the situation worse.

If you routinely “get heated” at work, the best-case scenario is that you’re part of a tight-knit team of confident people who aren’t put off by it2. No harm, no foul. But the second someone comes onto your team who’s not so confident, or you have to communicate outside of your team, it becomes a big problem. It’s a bad way to treat your colleagues — even undirected or casual anger intimidates and alienates the people around you3 — and it makes you a less effective engineer.

Healthy workplaces route around anger in the same way that networks route around damage. Emotionally unreliable engineers will get left out of conversations that might cause them to blow up. Decision-making will get done around them in backchannels. I’ve seen this become a self-reinforcing cycle: angry engineers aren’t consulted on key decisions, which makes them angrier, which pushes them even further away from the spaces where decisions get made, and so on.

You can often find these engineers bitterly complaining that they keep the company together, but nobody ever listens to them. In my experience4, this is almost never true. Engineers who are highly effective tend to get listened to — at minimum by their colleagues, and eventually by managers and product managers who want to extract as much value as possible from them. (One reason this is true is that all successful projects involve working with other people, and if nobody listens to you, you can’t do that.)

Caring

Why do angry engineers believe they’re important? Paradoxically, anger can be really useful to a software engineer. Angry engineers are rarely the ones holding the company together, but they’re also rarely useless.

One surprising thing about working for big tech companies is that some engineers are not just unproductive, but actively net-negative: either because they’re incapable of doing useful work on their own, or because they’re sloppy enough that they create more work than they do, or because they’re so checked out that they literally do nothing. Angry engineers might be net-negative in a cultural sense, but in terms of literally solving tickets and shipping features, they’re usually well above average.

Why is this? Anger often comes from caring about your work, and caring a lot is sufficient to make you a competent engineer. I’ve never worked with someone who genuinely cared about their work who wasn’t (or didn’t eventually become) competent. I actually think it’s healthy for an early-career engineer to sometimes get angry about their work, because it means they care a lot: it’s still a mistake in the moment, but it’s a “good mistake”.

I certainly used to get angry — in fact, I wrote about the angriest I’ve ever been at work here5. But you have to move past it.

Moving past anger

Think of “caring about your work” as a vertical tube, unsealed at either end. You fill the tube by pumping in emotional investment from the bottom6. If you have too little, it drains away and you end up as a useless coaster. But if you have too much, it overflows and you end up as an angry engineer that people have to work around.

One solution is to try and care the exact right amount: be invested in work a bit, but also have hobbies and a family and whatever else gives you perspective about your work problems. If you have a rich and healthy personal life, it’s hard to find yourself yelling at somebody about React state management. However, this is a tricky balance to maintain over time.

Another solution is to care about different things. The reason too much caring overflows into anger is because what you care about is misaligned with what the organization cares about. If your interests are perfectly aligned with your company’s (for instance, if you primarily care about delivering shareholder value), you can fit way more emotional investment into the tube before it overflows.

A little bit of “professional anger”

Here’s some dangerous advice: showing a little bit of anger at work can sometimes be useful. It can be a good way to signal that you care, or to build rapport with certain people, or to draw attention to something you think is important. However, it’s still always a mistake to be angry. You need to be able to drop back to a friendly mode at will, which is very difficult when you’re genuinely angry.

Being able to show a full range of emotion at work is good. It makes you more persuasive and more human. Being a fully professional robot is fine — you can have a successful career this way — but there’s always going to be some kind of uncanny-valley HR-ness to your work persona that will make it hard to connect with your colleagues.

If in doubt, don’t show anger. It’s never wrong to be professional. However, if you can signal that you’ve got enough distance to separate your professional feelings from your real feelings, and enough perspective to realize that the stakes of a technical decision are fundamentally not that high in the grand scheme of things, it can sometimes be okay to show visible frustration so that people know you’re still human.

Angry role models

Well-known software engineering personalities are often angry. It feels unfair to give too many negative examples, but obviously Linus Torvalds’ rants about Linux are a great example. Some of my favourite engineering talks are from Bryan Cantrill, who is sometimes visibly furious at his subject matter. There are too many well-known angry blog posts to list, but I’ll cite one I genuinely like: my Australian blogging colleague Nikhil’s post titled I Will Fucking Piledrive You If You Mention AI Again.

Anger is a part of the general image of a competent software engineer. Many junior engineers learn from this that it’s okay to be angry. However, taking your emotional cues from engineering celebrities is a big mistake, for a few reasons.

First, you are not Linus Torvalds or Bryan Cantrill. Torvalds is the BDFL of the most important software system in the world. Cantrill is the cofounder and CTO of his company. When these people are angry at work, people will not work around them, because they are the ones deciding what gets worked on. Once you’re the one in charge, you can get away with being emotional in the workplace7.

Second, you don’t know what it’s like to work with these engineers. People give talks and write blog posts because they’re emotionally worked up about something. If your only exposure to a celebrity is via their conference talks and blog posts, you’re seeing them at something like their maximum emotional intensity. If you then take that level of emotion into your normal everyday work, you’re almost certainly overshooting.

Anger is a local maximum

I’ve been reorged into dysfunctional teams, have had projects I enjoyed cancelled, and have worked on systems that were extremely chaotic. I can’t remember the last time I was actually angry at work. To be clear, I’m not successfully hiding my anger (unless it’s so repressed it’s invisible to me as well)8. Nor am I naturally a chill person. I’ve just reached a point in my career where I genuinely don’t get upset about work stuff.

A cynical person might say here that I’ve stopped caring about my work, so of course I don’t get angry anymore. I’ve left the side of the “real engineers” — the Linus Torvalds and Bryan Cantrills of the world — and sold out for that sweet, sweet big tech money. I mean, maybe! It’s true that I’m less invested in specific technical decisions than I used to be. But I still care a lot about doing a good job, I still spend a lot of time tweaking and reading code, and I certainly get more done than I did when I was more emotionally volatile.

Being angry at work feels good. It feels like proof that you’re working on something that matters, and that you’re personally having an impact. If you’re angry, nobody can call you a coaster. But anger is only a local maximum. If you can find your way to a different style of working, you’ll not only be more effective, but you’ll be in a far better place to have impact on problems that actually matter.

edit: this post got some good comments on Lobste.rs. One commenter argues that being angry at problems is better than being angry at people: I agree, but (a) if you’re in the habit of anger, it can be hard to keep it only directed at problems, and (b) when you express anger, the people around you are often impacted by it whether it’s directed at them or not. Other commenters recommend keeping a sense of perspective. Someone points out that it’s good to be angry at injustice. This is true: if your company is engaging in misconduct, you ought ot be angry about it. Finally, some commenters agree that anger can be a really effective tool for getting things done in the short-term.

It was also posted on Hacker News. The comments there aren’t as good, though I do recommend this one, which argues that if you don’t feel anger at work, you’re the victim of Marxist alienation. In fact, I agree! A long post is coming one of these days about how I learned to stop worrying and love Marxist alienation.

Here's a preview of a related post that shares tags with this one.

Read the whole story
emrox
1 day ago
reply
Hamburg, Germany
Share this story
Delete

AI Contribution Policies

1 Share

Your project, your rules.

A community collection of ready-made contribution policies. Whether you welcome AI contributions, want everything written by humans, or something in between.

Find your policy
  • AI Allowed

    Use any AI tooling you like. The usual contribution rules still apply.

    Permits
    • AI-generated code
    • AI-written text
    • Agent submissions
    • Private tooling
    Requires
    • Contribution guidelines
  • Human Voice

    AI can help you, but it must never speak or think for you.

    Permits
    • AI-generated code
    • Private tooling
    Requires
    • Contribution guidelines
    • Human authorship
    • Full ownership
    Forbids
    • Unreviewed AI output
  • Human Responsible

    Your tools are your business, but everything you submit must be yours.

    Requires
    • Contribution guidelines
    • Human authorship
    • Full ownership
    Forbids
    • AI disclosure notes
    • Unreviewed AI output
    • Unreproduced reports
  • AI Disallowed

    No AI at all. Every contribution must be the contributor’s own work.

    Requires
    • Contribution guidelines
    • Human authorship
    Forbids
    • Any AI assistance

How to use a policy

  1. Choose

    Compare the rules each policy sets and pick the one that fits.

  2. Copy

    Copy or download the Markdown and save it as AI_POLICY.md in your repository.

  3. Link

    Reference it from your CONTRIBUTING.md and pull request template.

Read the whole story
emrox
1 day ago
reply
Hamburg, Germany
Share this story
Delete

Don't be nice

1 Share
Published
Tags
open sourcevaluescommunity

Don't be nice.

Not many people know that the word 'nice' comes from the Latin 'nescius,' meaning 'unaware.' Words don't necessarily mean the same thing they did originally, but somehow, I think that is a little bit of what it is to be nice. You pull your own opinion back – to make space for other people.

But sometimes you shouldn't be nice.

Yesterday, I kicked someone from the Nuxt Discord who had chosen an avatar (for the second time!) of a man in a Nazi uniform.

I was not nice.

They accused me of being 'political' – the very thing an open source project shouldn't be, I'm told. It only divides people. Let's just focus on the technology. Surely we can all get behind building amazing, fast, cool websites!

No.

To be perfectly candid, I picked the Nazi example because I think we'll all agree on that – whatever your political persuasion.1

Sometimes a political party or a person decides to oppose shared human values like the importance of care, kindness, inclusion, or the simple value of welcoming people who are different from you. Maybe they oppose the equality of all people. Maybe they think some people do not deserve human rights.

When that happens, please, don't be nice. There's no 'both sides have a point.'

So I'm not going to be nice.

Let me say something else, seemingly more controversial.

DHH, you're not welcome in the Nuxt community, because you say that Black people aren't 'native Brits' and call for the mass deportation of 'gypsies'.

Now, I doubt he cares what I think. I'm not very important, and he doesn't really want to join.

But I mention it because the kinds of things that he's saying are being normalised. If you hear enough people say something it somehow becomes 'just another opinion.' And, because he's built a cool-looking Linux distribution (I love Arch, and those Omarchy screenshots are beautiful, by the way!) a lot of people seem to be thinking that the man himself (and his opinions) must be okay. Or at least, not worth making a fuss over.

I'm sorry. I'm not willing to be nice about this.

Check out this helpful article, DHH Is Way Worse Than I Thought. Jake said it better than I can:

DHH’s politics are not normal. Maybe they used to be, I don’t know, but as of right now the dude is way the fuck outside of what most people would consider moral or acceptable.

I would also like to see 1Password, DigitalOcean and others retract their support of DHH's pet project. I wouldn't judge someone who simply uses Omarchy. But can I ask you to think about it? It leaves a pretty bad taste in my mouth even to imagine using the product of someone who's suggested that Black and Asian Londoners make Britain worse.

Nice?

It's better to be good.


  1. An aside: I don't talk about party politics online. I talk about my values instead. And honestly, if someone positions themselves against those values I really feel that's on them – in much the same way as a scientist doesn't become 'political' just because a political party chooses to deny accepted science.


Comments

42 replies740 likes Reply on Bluesky

Just leaving this here: drewdevault.com/weird-guys/

Weird little guys of FOSS

65 likes16 reposts

Thanks this was eye opening and also depressing. Was not expecting to see ladybird and futo on there given the mission of the projects ☹️

Great list and good callout to rauch and dorsey- they are fully on board with trump

That list is getting long. It stings that Rauch is, rightfully, on it. I love Vercel, but...

oh shit I had no idea about Rossmann, ew

This is a great resource. ☝️

Andreas Kling? 😢💔 I looked at the sources and wow wtf he seems like the nicest guy in those monthly Ladybird updates I'm so confused right now, I really genuinely thought he was a great guy that is hugely disappointing 🙁

Man, there were a few that genuinely surprised me. Bummed.

This post reminds me of a pillow. My former head of people had a pillow in the background of her office that said, 'Be nice or get out.' It was prominently displayed in all meetings. In a world where there are many things to be, be a decent human being.

I'm framing this: > This post reminds me of a pillow.

If your definition of "not being nice" is "being mean" instead of "indifferent", then you just framed yourself. Good job! Escalation surely will help you rise to the highest point of attention. And then someone will be "nice" to you, just because they misunderstood a niche symbol you liked as right.

Understanding the paradox of tolerance should be the baseline.

35 likes1 repost

bravo

Image

10 likes

a step in the right direction. thanks for using your platform for good. now to address the Vercel issue in the room

4 likes

The tolerance paradox feels like it’s basically just game theory grim trigger strategy. Tolerate everyone, but as soon as they do something intolerant they should never be tolerated again.

10 likes1 repost

In some circles a true self-redemption obviates that never.

I believe in redemption

as hard as it could be to believe for some, there is no telling how much good someone can put in to the world once they realize and turn from their bad decisions/words/actions/etc

Apology Not Accepted is a great read for redemption scenarios www.the-reframe.com/apology-not-... In summary; don’t accept fake apology by those who want to abuse your goodwill, redemption takes real work

kind, not nice, yes.

8 likes

💯 % Another reason for me to like @nuxt.com

8 likes

I've also been exploring this lately. It's challenging because my entire life has revolved around pleasing others. On the topic, it's harsh to see a thought leader meltdown. Wonder if it might be related to a midlife crisis (no offense, I'm approaching one too). People tend to radicalize then.

1 like1 repost

Well said. I hosted a local meetup, and every now and then there was someone who would hijack the conversations to keep spreading their own weird ideas… But IRL it’s really hard to kick them out, even when I knew I had to. And when I did it was so difficult and thankless.

5 likes

Those people would be sore at me and would have no idea what happened (which makes sense), they would insult our community for rejecting them… But I just remember this initial urge to “be nice” and try to avoid kicking them out in the first place… But I had to not be nice.

Kudos for taking a stand. I'm reminded of this quote by Charles Bukowski: "The problem with the world is that the intelligent people are full of doubts, while the stupid ones are full of confidence."

12 likes

As someone who moderated a tech-focused community for several years, it took me a while to develop the sense to drop my usual nuance-focused thinking, And be more prompt in acting against disruptors acting in bad faith, particularly politically. Such users don't respond to tact.

Fuck these nazi pieces of shit, *especially* when they try to take some weird moral high ground about tech being apolitical

16 likes2 reposts

Fuck em, name em and shame em.

Thank you brother.

3 likes

Thank you for drawing a clear line. Some things don't deserve a nice response, and saying so out loud is exactly the kind of decency that's getting rare.

2 likes1 repost

The community is one of the best parts of Nuxt. Thank you for being a great steward 🙏

1 like1 repost

the timing! (literally yesterday)

Image

5 likes

(i (and probably we) agree with your blog post tho)

oh heavens! no subposting intended 😆 where is this?

this was emberfest in Prague! and was a good talk! (partly about remembering that there are humans on the other side of the screen)

If that's good as in good vs evil, not just sometimes

1 like

Words to live by. Respect!

1 like2 reposts

Nice is different than good. (Into the Woods)

it's impossible to be nice to everyone is the thing. if you continue to be nice to Alice after Alice has expressed her desire to ethnically cleanse Bob, Bob is going to draw the obvious conclusions. you have to choose

2 likes

A lot of others mentioned what I think, esp. Karl Popper. So I'm here to say that you are important.

3 likes1 repost

I agree on everything you said, and i hate DHH since the day he was trash tweeting about Muslims

1 like1 repost

Having a spine and sticking to your values is more important that appearing nice or polite to those who would roll over you without flinching

5 likes1 repost

This is why kindness will always be infinitely more valuable than niceness. Thank you, Daniel 💜

1 like

Well said (and beautifully expressed).

3 likes1 repost

Great essay. Personally I think the way of making things better is to have zero tolerance for people with these beliefs in our communities. But at the same time I think we could benefit from deeply understanding them and why they hold such repugnant beliefs.

1 repost

Well said! And your aside is worth repeating: "...if someone positions themselves against [my] values I really feel that's on them – in much the same way as a scientist doesn't become 'political' just because a political party chooses to deny accepted science."

2 likes1 repost

This guy showed his fangs quite some time ago. I noticed it when i saw this post where he intentionally picked/ignored relevant data to the statistics that the original report had back in Jan 2025: x.com/dhh/status/1... and someone called him out for it: x.com/IndieCEO/sta...

this is really disappointing. nuxt does not belong to you, it belongs to all of us. you should not be the moral arbiter no matter how righteous you believe your cause. leave nuxt out of this.

you can read what I've written about why this is EXACTLY my role in leading nuxt > I would be remiss not to speak about values. > Values shape the direction of projects and people [and] the culture of open source communities […] both in where we end up + what the journey there is like.

Diversity, equity and inclusion

Diversity, equity and inclusion

I'm in favour of diversity, equity and inclusion in open source communities, and here's why I think it matters.

Just your section on politics alone is wonderful.

Keep doing what you do! We need more people with reach who speak up for these values, especially these days. And of course Nuxt is (and should) be a part of that.

Everything is political, I have learnt to never let anyone convince me it is not. Amazing article. I also didn't know about the DHH stuff, thanks for leaving that in, I will avoid omarchy.

If you don't like the way Nuxt is led, fork it.

Given that the article is about kicking a Nazi off discord i can only assume you’re here to defend nazis.

You argue companies should reconsider sponsoring Omarchy over DHH’s views. How do you apply that principle to working at Vercel, given DeVault’s concerns about CEO Guillermo Rauch and board member Mitchell Hashimoto? If DHH joined Vercel’s board, would that change anything?

3 likes2 reposts

I only ask because I think this is sadly a situation more people are going to have to wrestle with, especially given the current job market and how difficult it can be to choose who you work for or with.

Don't forget that everyone using Shopify has to find a new home too since DHH and Toby are good friends and DHH is on the board of Shopify also

WoW! I was not expecting this when I started to read. Thank you very much for writing this and being who you are. 🫶

1 like

Read the whole story
emrox
1 day ago
reply
Hamburg, Germany
Share this story
Delete
Next Page of Stories