Full-Stack Dart for the
JavaScript Ecosystem

Write React, React Native, and Express applications entirely in Dart. One language. Runtime type safety. Sound null safety. No compromises.

// A complete Express server in Dart
import 'package:dart_node_express/dart_node_express.dart';

void main() {
  final app = createExpressApp();

  app.get('/', (req, res) {
    res.json({'message': 'Hello from Dart!'});
  });

  app.listen(3000, () {
    print('Server running on port 3000');
  });
}

Built for You

Whether you're coming from React or Flutter, dart_node speaks your language.

React (TypeScript)
const Counter: React.FC = () => {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount(c => c + 1)}>
      Count: {count}
    </button>
  );
};
React (Dart)
ReactElement counter() {
  final (count, setCount) = useState(0);

  return button(
    onClick: (_) => setCount((c) => c + 1),
    children: [text('Count: $count')],
  );
}
1

Same Paradigms

Hooks, components, props, state — everything you know from React works the same way in Dart.

2

Runtime Type Safety

Unlike TypeScript, Dart preserves types at runtime. No more any escapes or erased generics.

3

Simpler Tooling

No webpack, no babel, no tsconfig. Just dart compile js and you're done.

Flutter
class Counter extends StatefulWidget {
  @override
  State<Counter> createState() => _CounterState();
}

class _CounterState extends State<Counter> {
  int count = 0;

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: () => setState(() => count++),
      child: Text('Count: $count'),
    );
  }
}
dart_node React
ReactElement counter() {
  final (count, setCount) = useState(0);

  return button(
    onClick: (_) => setCount((c) => c + 1),
    children: [text('Count: $count')],
  );
}
1

Same Language

Use your existing Dart skills. Share models, utilities, and business logic across platforms.

2

Web Ecosystem Access

Leverage the massive React and npm ecosystems while writing pure Dart code.

3

Full-Stack Dart

Backend (Express), web (React), mobile (React Native) — all in one language.

The dart_node Stack

Five packages that give you full-stack superpowers.

C

dart_node_core

Foundation layer with JS interop utilities, Node.js bindings, and console helpers.

Learn more →
E

dart_node_express

Type-safe Express.js bindings for building HTTP servers and REST APIs.

Learn more →
R

dart_node_react

React bindings with hooks, JSX-like syntax, and full component support.

Learn more →
N

dart_node_react_native

React Native + Expo bindings for cross-platform mobile development.

Learn more →
W

dart_node_ws

WebSocket bindings for real-time communication on Node.js.

Learn more →

Why Types Matter at Runtime

TypeScript erases types when it compiles to JavaScript. Dart doesn't.

TypeScript (Types Erased)
interface User {
  id: number;
  name: string;
}

// At runtime, this is just a plain object
// No way to validate the shape!
const user: User = JSON.parse(data);

// This could fail silently
console.log(user.name.toUpperCase());
// Runtime error if name is undefined!
Dart (Types Preserved)
class User {
  final int id;
  final String name;
  User({required this.id, required this.name});
}

// Types exist at runtime - you can validate!
final user = User.fromJson(jsonDecode(data));

// If name were null, this would fail
// at deserialization, not at usage
print(user.name.toUpperCase());

Get Started in Minutes

# Create a new project
mkdir my_dart_app && cd my_dart_app
dart create -t package .

# Add dart_node packages
dart pub add dart_node_core dart_node_express

# Write your server
cat > lib/server.dart << 'EOF'
import 'package:dart_node_express/dart_node_express.dart';

void main() {
  final app = createExpressApp();
  app.get('/', (req, res) => res.send('Hello, Dart!'));
  app.listen(3000);
}
EOF

# Compile to JavaScript and run
dart compile js lib/server.dart -o build/server.js
node build/server.js