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.
const Counter: React.FC = () => {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(c => c + 1)}>
Count: {count}
</button>
);
};
ReactElement counter() {
final (count, setCount) = useState(0);
return button(
onClick: (_) => setCount((c) => c + 1),
children: [text('Count: $count')],
);
}
Same Paradigms
Hooks, components, props, state — everything you know from React works the same way in Dart.
Runtime Type Safety
Unlike TypeScript, Dart preserves types at runtime. No more any escapes or erased generics.
Simpler Tooling
No webpack, no babel, no tsconfig. Just dart compile js and you're done.
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'),
);
}
}
ReactElement counter() {
final (count, setCount) = useState(0);
return button(
onClick: (_) => setCount((c) => c + 1),
children: [text('Count: $count')],
);
}
Same Language
Use your existing Dart skills. Share models, utilities, and business logic across platforms.
Web Ecosystem Access
Leverage the massive React and npm ecosystems while writing pure Dart code.
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.
dart_node_core
Foundation layer with JS interop utilities, Node.js bindings, and console helpers.
Learn more →dart_node_express
Type-safe Express.js bindings for building HTTP servers and REST APIs.
Learn more →dart_node_react
React bindings with hooks, JSX-like syntax, and full component support.
Learn more →dart_node_react_native
React Native + Expo bindings for cross-platform mobile development.
Learn more →Why Types Matter at Runtime
TypeScript erases types when it compiles to JavaScript. Dart doesn't.
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!
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