Any modern languages should have its REPL, Erlang, Elixir, Haskell, Clojure, Ocaml, Python... All of them got one shell-like feature to interact with the application in conception phase. That's kinda mandatory to me, it permits to test functions before adding them in the final commit, it can be used to draft quick ideas and so on. When I started learning Dart, I was a bit sad it was not integrated by default... but someone decided to fix that by creating the interactive package! Let create a new project called myrepl just to check that.
$ dart create myrepl
Creating myrepl using template console...
.gitignore
analysis_options.yaml
CHANGELOG.md
pubspec.yaml
README.md
bin/myrepl.dart
lib/myrepl.dart
test/myrepl_test.dart
Running pub get... 0.3s
Resolving dependencies...
Downloading packages...
Changed 48 dependencies!
Created project myrepl in myrepl! In order to get started, run the following commands:
cd myrepl
dart run
$ cd myrepl
As usual, the new dependency can be added using dart pub add. interactive depends on 12 dependencies, so, it could be better to add it only in the dev environment.
$ dart pub add interactive
Resolving dependencies...
Downloading packages...
< _fe_analyzer_shared 85.0.0 (was 100.0.0) (100.0.0 available)
< analyzer 7.7.1 (was 13.0.0) (13.0.0 available)
+ cli_repl 0.2.3
< coverage 1.6.4 (was 1.15.0) (1.15.0 available)
+ interactive 1.4.1
+ js 0.6.7 (0.7.2 available)
< matcher 0.12.17 (was 0.12.20) (0.12.20 available)
< test 1.26.3 (was 1.31.1) (1.31.1 available)
< test_api 0.7.7 (was 0.7.12) (0.7.12 available)
< test_core 0.6.12 (was 0.6.18) (0.6.18 available)
< vm_service 11.10.0 (was 15.2.0) (15.2.0 available)
These packages are no longer being depended on:
- cli_config 0.2.0
Changed 12 dependencies!
9 packages have newer versions incompatible with dependency constraints.
Try `dart pub outdated` for more information
Next, interactive package must be compiled and activated on the system. It will be installed locally in ${HOME}/.pub-cache/bin directory.
$ dart pub global activate interactive
Package interactive is currently active at version 1.4.1.
Downloading packages... .
_fe_analyzer_shared 85.0.0 (100.0.0 available)
analyzer 7.7.1 (13.0.0 available)
js 0.6.7 (0.7.2 available)
> meta 1.18.3 (was 1.18.2)
vm_service 11.10.0 (15.2.0 available)
Building package executables... (2.5s)
Built interactive:interactive.
Installed executable interactive.
Warning: Pub installs executables into $HOME/.pub-cache/bin, which is not on your path.
You can fix that by adding this to your shell's config file (.bashrc, .bash_profile, .zshrc etc.):
export PATH="$PATH":"$HOME/.pub-cache/bin"
Activated interactive 1.4.1.
$ file ${HOME}/.pub-cache/bin/interactive
${HOME}/.pub-cache/bin/interactive: a sh script, ASCII text executable
The ${HOME}/.pub-cache/bin/interactive file is a simple shell script using the dart VM to execute the interactive package. The command executed looks like the snippet below. It means this code could be executed anywhere on your system if the interactive package is installed (it will produce some errors outside a Dart project directory).
dart pub -v global run interactive:interactive "$@"
Anyway, let export the Dart bin directory inside our PATH.
$ export PATH="${PATH}:${HOME}/.pub-cache/bin"
Great! Let execute the interactive command (it should be present in our PATH now).
$ interactive
Run: /bin/dart [--enable-vm-service=34273, file:///bin/interactive.dart-3.11.5.snapshot, --vm-service-was-enabled]
Workspace: /tmp/dart_interactive_workspace_2026-06-04T163359990891
The Dart VM service is listening on http://127.0.0.1:34273/HveG-LmYIiQ=/
The Dart DevTools debugger and profiler is available at: http://127.0.0.1:34273/HveG-LmYIiQ=/devtools/?uri=ws://127.0.0.1:34273/HveG-LmYIiQ=/ws
>>>
The command invoke a shell with a >>> prompt. What will happen if we create some Dart code?
>>> 1+1
2
>>> class Meh { String _meh = ""; Meh(String meh) : this._meh = meh; String toString() => "${_meh}!"; }
>>> Meh("test")
test!
>>> import 'dart:async';
>>> Future<int> t() { return 1; }
[WARNING 2026-06-04 20:25:05.859183] Error: Hot reload failed, maybe because code has syntax error?
>>> Future<int> t() async { return 1; }
>>> t().then((x) => print(x))
Instance of 'Future<void>'
>>> 1
It works! interactive gives us a way to dynamically create Dart code, like any modern language! That's very cool! It's even possible to execute command from the system itself by prefixing the line to execute with !.
>>> !ls
lib
pubspec.lock
pubspec.yaml
>>> !pwd
/tmp/dart_interactive_workspace_2026-06-04T201405364736
Conclusion
This is a great project, and it could be even better to see it be added in the SDK! At this time, it works, but it feels like it's a bit unstable and not finished yet. The shell is working but can be slow sometimes. The fact the devtools are already started by default is also another nice feature. What's missing to me? Here a quick list of cool stuff to add:
adding a successful command line index counter, every time a command is being executed, the counter is increased;
removing the "..." for the multi line support, it can be annoying when doing a copy/paste;
integrating the
devtoolsdirectly into the shell, like@profileto profile the application or@memoryto see memory usage;saved session with state and command history restore;
debugger and tracer integration;
documentation and manual integration like
help(Object);class, function and command Auto-completion when pressing tab;
handlers, hooks and other features to make a custom shell.
As usual, if you want to know more about this project, here some links:
The
interactivepackage at pub.dev;The official
interactivepackage source code at Github;
Bonus: devtools
While testing interactive I discovered the Dart devtools suite. It's a pretty cool way to debug, trace and profile a Dart application, thanks to the Dart virtual machine. This application is working a bit like the different tools we have with the BEAM (e.g. observer, debugger and so on). Here some screenshot from the previous project created.
A full post on this feature will be required. For now, it's just a quick overview based on screenshots.
Cover Image by Giulia May on Unsplash





Top comments (0)