Skip to content

Commit 0c3d6da

Browse files
Critique and improve server component directives (#520)
* Add section on directives' limitations and API alternatives Co-authored-by: tannerlinsley <tannerlinsley@gmail.com> * Refactor blog post to remove unnecessary sections Co-authored-by: tannerlinsley <tannerlinsley@gmail.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
1 parent 275f9fa commit 0c3d6da

File tree

1 file changed

+50
-0
lines changed

1 file changed

+50
-0
lines changed

src/blog/directives-the-new-framework-lock-in.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,50 @@ We are already seeing confusion in the wild. Many developers now believe `use cl
3636

3737
---
3838

39+
### Credit where it's due: `use server` and `use client`
40+
41+
Some directives exist because multiple tools needed a single, simple coordination point. In practice, `use server` and `use client` are pragmatic shims that tell bundlers and runtimes where code is allowed to execute in an RSC world. They have seen relatively broad support across bundlers precisely because the scope is narrow: execution location.
42+
43+
That said, even these show the limits of directives once real-world needs appear. At scale, you often need parameters and policies that matter deeply to correctness and security: HTTP method, headers, middleware, auth context, tracing, caching behaviors, and more. Directives have no natural place to carry those options, which means they are frequently ignored, bolted on elsewhere, or re-encoded as new directive variants.
44+
45+
### The real offenders: option-laden directives and directive-adjacent APIs
46+
47+
When a directive immediately, or soon after creation, needs options or spawns siblings (e.g., `'use cache:remote'`) and helper calls like `cacheLife(...)`, that’s a strong signal the feature wants to be an API, not a string at the top of a file. If you know you need a function anyway, just use a function for all of it.
48+
49+
Examples:
50+
51+
```js
52+
'use cache:remote'
53+
const fn = () => 'value'
54+
```
55+
56+
```js
57+
// explicit API with provenance and options
58+
import { cache } from 'next/cache'
59+
export const fn = cache(() => 'value', {
60+
strategy: 'remote',
61+
ttl: 60,
62+
})
63+
```
64+
65+
And for server behavior where details matter:
66+
67+
```js
68+
import { server } from '@acme/runtime'
69+
70+
export const action = server(async (req) => {
71+
return new Response('ok')
72+
}, {
73+
method: 'POST',
74+
headers: { 'x-foo': 'bar' },
75+
middleware: [requireAuth()],
76+
})
77+
```
78+
79+
APIs carry provenance (imports), versioning (packages), composition (functions), and testability. Directives don’t — and trying to smuggle options into them quickly becomes a design smell.
80+
81+
---
82+
3983
### A Shared Syntax Without a Shared Spec Is a Fragile Foundation
4084

4185
Once multiple frameworks start adopting directives, we end up in the worst possible state:
@@ -185,6 +229,12 @@ Directives should be rare, stable, and standardized, not multiplied by every ven
185229

186230
---
187231

232+
### This is not the JSX/virtual DOM moment
233+
234+
It’s tempting to compare criticism of directives to the early skepticism around React’s JSX or the virtual DOM. I get the sentiment, but the failure modes are different. JSX and the VDOM did not masquerade as language features; they came with explicit imports, provenance, and tooling boundaries. Directives, by contrast, live at the top-level of files and look like the platform, which creates ecosystem expectations and tooling burdens without a shared spec.
235+
236+
---
237+
188238
### The Bottom Line
189239

190240
Framework directives might feel like DX magic today, but the current trend points toward a fractured future, JavaScript dialects defined not by standards, but by vendors.

0 commit comments

Comments
 (0)