dart_nostr
A Dart/Flutter library for building Nostr clients. Built with simplicity in mind, dart_nostr handles the complexity of the Nostr protocol so you can focus on creating great user experiences.
What is Nostr?
Nostr (Notes and Other Stuff Transmitted by Relays) is a simple, open protocol for global, decentralized, and censorship-resistant social media. This library gives you everything you need to build Nostr clients in Dart or Flutter.
Features
- Complete key management (generation, derivation, encoding/decoding)
- Event creation, signing, and verification
- WebSocket relay connections with automatic reconnection
- Event subscriptions with stream and future-based APIs
- Support for 40+ NIPs out of the box
- NIP-05 verification
- NIP-19 entity encoding (nevent, nprofile, etc.)
- Proof of work support (NIP-13)
- And much more
Supported NIPs
Currently implements: 01, 02, 03, 04, 05, 06, 08, 09, 10, 11, 13, 14, 15, 18, 19, 21, 23, 24, 25, 27, 28, 30, 31, 32, 36, 38, 39, 40, 45, 47, 48, 50, 51, 52, 53, 56, 57, 58, 72, 75, 78, 84, 89, 94, 98, 99.
Note: NIP-42 and NIP-44 are planned for future releases. Platform-specific NIPs like NIP-07 (web browser extensions) aren't directly applicable to this library.
Getting Started
Add dart_nostr to your pubspec.yaml:
dependencies:
dart_nostr: ^9.2.4
Or use the command line:
flutter pub add dart_nostr # Flutter
dart pub add dart_nostr # Dart
Quick Example
Here's a simple example to get you started:
import 'package:dart_nostr/dart_nostr.dart';
void main() async {
// Initialize
final nostr = Nostr.instance;
// Generate keys
final keyPair = nostr.keysService.generateKeyPair();
print('Public key: ${keyPair.public}');
// Connect to relays
await nostr.relaysService.init(
relaysUrl: ['wss://relay.damus.io', 'wss://nos.lol'],
);
// Create and publish an event
final event = NostrEvent.fromPartialData(
kind: 1,
content: 'Hello Nostr!',
keyPairs: keyPair,
);
nostr.relaysService.sendEventToRelays(event);
// Subscribe to events
final stream = nostr.relaysService.startEventsSubscription(
request: NostrRequest(filters: [
NostrFilter(kinds: [1], limit: 10),
]),
);
stream.stream.listen((event) {
print('Received: ${event.content}');
});
}
Usage Guide
Working with Instances
You can use dart_nostr in two ways depending on your needs:
// Singleton - shared state across your app
final nostr = Nostr.instance;
// Multiple instances - isolated state
final nostr1 = Nostr();
final nostr2 = Nostr(); // Completely independent
Most apps work well with the singleton. Use multiple instances if you need to connect to different relay sets simultaneously or want to isolate different parts of your app.
Keys
Generate New Keys
final keyPair = nostr.keysService.generateKeyPair();
print(keyPair.public); // Your public key
print(keyPair.private); // Keep this secret!
Work with Existing Keys
// If you already have a private key
final keyPair = nostr.keysService
.generateKeyPairFromExistingPrivateKey(myPrivateKey);
Sign and Verify Messages
final signature = nostr.keysService.sign(
privateKey: keyPair.private,
message: "GM",
);
final isValid = nostr.keysService.verify(
publicKey: keyPair.public,
message: "GM",
signature: signature,
);
Bech32 Encoding (nsec/npub)
// Encode to human-friendly formats
final nsec = nostr.keysService.encodePrivateKeyToNsec(privateKey);
final npub = nostr.keysService.encodePublicKeyToNpub(publicKey);
// Decode back
final privateKey = nostr.keysService.decodeNsecKeyToPrivateKey(nsec);
final publicKey = nostr.keysService.decodeNpubKeyToPublicKey(npub);
Events
Create and Sign Events
The easiest way:
final event = NostrEvent.fromPartialData(
kind: 1, // Text note
content: 'Hello Nostr!',
keyPairs: keyPair,
tags: [
['p', 'pubkey_to_mention'],
['e', 'event_id_to_reference'],
],
);
// Event is already signed and has an ID
print(event.id);
print(event.sig);
Relays
Connect to Relays
await nostr.relaysService.init(
relaysUrl: [
'wss://relay.damus.io',
'wss://nos.lol',
'wss://relay.nostr.band',
],
);
Subscribe to Events
Real-time streaming:
final stream = nostr.relaysService.startEventsSubscription(
request: NostrRequest(filters: [
NostrFilter(
kinds: [1],
authors: [keyPair.public],
limit: 50,
),
]),
);
stream.stream.listen((event) {
print(event.content);
});
// Don't forget to close when done
stream.close();
One-time fetch (waits for EOSE):
final events = await nostr.relaysService.startEventsSubscriptionAsync(
request: NostrRequest(filters: [
NostrFilter(kinds: [1], limit: 20),
]),
);
print('Got ${events.length} events');
Publish Events
nostr.relaysService.sendEventToRelays(event);
// Or wait for confirmation
final ok = await nostr.relaysService.sendEventToRelaysAsync(event);
print(ok.message);
More Features
NIP-05 Verification
final verified = await nostr.utilsService.verifyNip05(
internetIdentifier: "user@domain.com",
pubKey: publicKey,
);
NIP-19 Entities
// Create shareable event links
final nevent = nostr.utilsService.encodeNevent(
eventId: event.id,
pubkey: keyPair.public,
userRelays: ['wss://relay.damus.io'],
);
// Create profile links
final nprofile = nostr.utilsService.encodeNProfile(
pubkey: keyPair.public,
userRelays: ['wss://relay.damus.io'],
);
Event Counting
final countEvent = NostrCountEvent.fromPartialData(
eventsFilter: NostrFilter(kinds: [1], authors: [keyPair.public]),
);
final count = await nostr.relaysService.sendCountEventToRelaysAsync(countEvent);
print('User has ${count.count} text notes');
Relay Information
final info = await nostr.relaysService.relayInformationsDocumentNip11(
relayUrl: "wss://relay.damus.io",
);
print(info?.name);
print(info?.supportedNips);
Examples
The example directory contains runnable examples showing:
- Basic key management
- Creating and publishing events
- Subscribing to event streams
- Working with different event kinds
- NIP-05 verification flows
- And more real-world scenarios
API Documentation
Full API documentation is available at pub.dev.
Contributing
Found a bug? Have a feature idea? Contributions are welcome!
- Check existing issues or create a new one
- Fork the repository
- Create your feature branch
- Make your changes
- Submit a pull request
Please ensure your code follows the existing style and includes tests where appropriate.
License
MIT License - see LICENSE for details.
Links
Questions?
- Open an issue
- Start a discussion
Libraries
- dart_nostr
- nostr/core/constants
- nostr/core/exceptions
- nostr/core/extensions
- nostr/core/key_pairs
- nostr/core/utils
- nostr/dart_nostr
- nostr/instance/bech32/bech32
- nostr/instance/keys/keys
- nostr/instance/registry
- nostr/instance/relays/base/relays
- nostr/instance/relays/relays
- nostr/instance/streams
- nostr/instance/tlv/base/base
- nostr/instance/tlv/tlv_utils
- nostr/instance/utils/utils
- nostr/instance/web_sockets
- nostr/model/base
- nostr/model/count
- nostr/model/debug_options
- nostr/model/ease
- nostr/model/event/event
- nostr/model/export
- nostr/model/nostr_event_key
- nostr/model/nostr_events_stream
- nostr/model/notice
- nostr/model/ok
- nostr/model/relay
- nostr/model/relay_informations
- nostr/model/request/close
- nostr/model/request/eose
- nostr/model/request/filter
- nostr/model/request/request
- nostr/model/tlv
- nostr/service/services