V7 Nylo v7 is here! See what's new →
Nylo
Flutter micro-framework MIT licensed

The Flutter
Micro-framework
For Modern Apps

Nylo gives every project the same solid foundation — routing, state, networking, forms and auth — so you start at feature one instead of file one.

Install in one line
$ dart pub global activate nylo_installer
Read the installation guide Then follow the prompts to name your project.
my_app SCAFFOLDED
lib/
app/  — models, networking, providers
bootstrap/  — boot & setup
config/  — theme, keys, decoders
resources/
pages/  home_page.dart
widgets/
themes/
routes/  router.dart
main.dart
Every Nylo project lands in the same shape — so does every teammate's.
861 ★ on GitHub Dart 3 compatible MIT licensed Published by nylo.dev on pub.dev Actively maintained since 2021
>_ Metro CLI

Create anything from the terminal

Metro scaffolds pages, models, controllers, widgets and more — wired into your router and folder structure, not dumped in a corner.

17 generators covering widgets, app plumbing and config
Routes registered automatically on generate
Consistent naming and file placement across the team
Learn more about Metro
zsh — my_app
$ metro make:page HomePage
  ✓ Created lib/resources/pages/home_page.dart
$ metro make:api_service User
  ✓ Created lib/app/networking/user_api_service.dart
$ metro make:model User
  ✓ Created lib/app/models/user.dart
$ metro make:stateful_widget FavouriteWidget
app/networking/api_service.dart
class ApiService extends NyApiService {
  @override
  String get baseUrl => "https://api.example.com/v1";

  Future<List<Post>> posts() async {
    return await network(
      request: (request) => request.get("/posts"),
    );
  }
}

// Usage in your page
final posts = await api<ApiService>((request) => request.posts());
Networking

Effortless API integration

Write clean, maintainable API services with automatic JSON parsing, error handling and request interceptors — no Dio boilerplate in your pages.

Learn more about Networking
Explore

See it in the code you'd actually write

routes/router.dart
appRouter() => nyRoutes((router) {
    router.add(HomePage.path).initialRoute();

    router.add(DiscoverPage.path);

    router.add(LoginPage.path, 
        transitionType: TransitionType.bottomToTop());

    router.add(ProfilePage.path,
        routeGuard: [
            AuthGuard()
        ]
    );
});

Build complex routes, interfaces and UI pages for your Flutter application.

Learn more
Step 1

Authenticate a user

String userToken = "eyJhbG123...";

await Auth.authenticate(data: {"token": userToken});
Step 2

Now, when your user opens the app they will be authenticated.

final userData = Auth.data();
// {"token": "eyJhbG123..."}

bool isAuthenticated = await Auth.isAuthenticated();
// true
Step 3

If you've set an authenticatedRoute in your router, then it will present this page when the user opens the app again.

routes/router.dart
appRouter() => nyRoutes((router) {
    ...
    router.add(LandingPage.path).initialRoute();

    router.add(DashboardPage.path).authenticatedRoute();
    // overrides the initial route when a user is authenticated

Logout the user

await Auth.logout();

Authenticate users in your Flutter application.

Learn more
Step 1

Create a Form

terminal
metro make:form RegisterForm
Step 2

Modify your form

app/forms/register_form.dart
class RegisterForm extends NyFormWidget {

    RegisterForm({super.key, super.submitButton, super.onSubmit, super.onFailure});

    // Add your fields here
    @override
    fields() => [
        Field.capitalizeWords("name",
            label: "Name",
            validator: FormValidator.notEmpty(),
        ),
        Field.email("email_address",
            label: "Email",
            validator: FormValidator.email()
        ),
        Field.password("password",
            label: "Password",
            validator: FormValidator.password(),
        ),
    ];

    static NyFormActions get actions => const NyFormActions("RegisterForm");
}
Step 3

Use your form in a widget

register_page.dart
@override
Widget build(BuildContext context) {
  return Scaffold(
    body: RegisterForm(
      submitButton: Button.primary(text: "Submit"),
      onSubmit: (data) {
        printInfo(data);
      },
    ),
  );
}

Manage, validate and submit data all in one place with Nylo Forms.

Learn more
Step 1

Create a state managed widget

terminal
metro make:stateful_widget CartIcon
resources/cart_icon_widget.dart
class _CartIconState extends NyState<CartIcon> {
  ...

  @override
  Map<String, Function> get stateActions => {
    "clear_cart": () {
      _items = 0;
    },
    ...
  };

  @override
  Widget view(BuildContext context) {
    return Container(child: Text("Items in cart: ${_items}"));
  }
}
Step 2

Use CartIcon.action("clear_cart")

another widget
Button.primary(text: "Add to cart",
    onPressed: () {
      CartIcon.action("clear_cart");
    }
)

Powerful state management for widgets in your Flutter application.

Learn more
Step 1

Create your event

terminal
metro make:event Logout
app/events/logout_event.dart
class LogoutEvent implements NyEvent {
    @override
    final listeners = {
        DefaultListener: DefaultListener(),
    };
}

class DefaultListener extends NyListener {
    @override
    handle(dynamic event) async {

        // logout user
        await Auth.logout();

        // redirect to home page
        routeTo(HomePage.path,
            navigationType: NavigationType.pushAndForgetAll
        );
    }
}
Step 2

Dispatch the event

MaterialButton(child: Text("Logout"),
    onPressed: () {
        event<LogoutEvent>();
    },
)

Dispatch events and listen for them in your application.

Learn more

Schedule a task to run once

Nylo.scheduleOnce("onboarding_info", () {
    print("Perform code here to run once");
});

Schedule a task to run once after a specific date

Nylo.scheduleOnceAfterDate("app_review_rating", () {
    print("Perform code to run once after DateTime(2025, 04, 10)");
}, date: DateTime(2025, 04, 10));

Schedule a task to run once daily

Nylo.scheduleOnceDaily("free_daily_coins", () {
    print("Perform code to run once daily");
});

Schedule tasks to run once or daily in your Flutter application.

Learn more
Step 1

Create an API Service

terminal
metro make:api_service User
app/networking/user_api_service.dart
class UserApiService extends NyApiService {
    @override
    String get baseUrl => getEnv("API_BASE_URL");

    Future<User?> fetchUser(int id) async {
        return await get<User>(
            "/users/$id",
            queryParameters: {"include": "profile"},
        );
    }

    Future<User?> createUser(Map<String, dynamic> data) async {
        return await post<User>("/users", data: data);
    }
}
Step 2

Call the API from your page

User? user = await api<UserApiService>(
    (request) => request.fetchUser(1),
);

Elegant API services with automatic JSON parsing, caching, and interceptors.

Learn more
Step 1

Save data securely

saving_data.dart
// Save values to secure storage
await NyStorage.save("coins", 100);
await NyStorage.save("username", "Anthony");
await NyStorage.save("isPremium", true);

// Save with TTL (auto-expires)
await NyStorage.save("session", "abc123",
    expiry: Duration(hours: 1),
);
Step 2

Read with type casting

// Automatic type casting
String? username = await NyStorage.read("username");
int? coins = await NyStorage.read<int>("coins");
bool? isPremium = await NyStorage.read<bool>("isPremium");

// Delete a value
await NyStorage.delete("coins");

Secure local storage with type casting, TTL expiry, and collections.

Learn more
Step 1

Add your language files

lang/en.json
{
    "welcome": "Welcome",
    "greeting": "Hello {{name}}",
    "navigation": {
        "home": "Home",
        "profile": "Profile"
    }
}
Step 2

Translate text in your widgets

// Simple translation
Text("welcome".tr())  // "Welcome"

// With arguments
Text("greeting".tr(arguments: {"name": "Anthony"}))
// "Hello Anthony"

// Nested keys
Text("navigation.home".tr())  // "Home"

Multi-language support with JSON files, arguments, and RTL.

Learn more
Step 1

Create a Navigation Hub

terminal
metro make:navigation_hub base
resources/pages/base_navigation_hub.dart
class _BaseNavigationHubState extends NavigationHub<BaseNavigationHub> {

    NavigationHubLayout? layout = NavigationHubLayout.bottomNav();

    @override
    bool get maintainState => true;

    _BaseNavigationHubState() : super(() async {
        return {
            0: NavigationTab(
                title: "Home",
                page: HomeTab(),
                icon: Icon(Icons.home),
            ),
            1: NavigationTab(
                title: "Settings",
                page: SettingsTab(),
                icon: Icon(Icons.settings),
            ),
        };
    });
}
Step 2

Switch layouts easily

// Bottom navigation
NavigationHubLayout.bottomNav()

// Top navigation
NavigationHubLayout.topNav()

// Journey / wizard flow
NavigationHubLayout.journey()

Build bottom nav, top nav, or journey flows with state maintenance.

Learn more
Community

Built in the open, used in production

“I'm new to Dart and new to your framework — which I love.”

P
Peter
Senior Director, Heroku Global

“Nylo is the best framework for Flutter — it makes developing easy.”

@higakijin

“By far the best framework out there. Amazing quality and features.”

@2kulfi

“It makes the work easier and less time consuming. Great work.”

darkreader01

“Just discovered this framework and I'm very impressed. Thank you.”

@lepresk

“Really love the concept of this framework.”

@Chrisvidal

“I wanted to thank you guys for the great job you are doing.”

@youssefKadaouiAbbassi

“Just to say that I am in love with @nylo_dev's website!”

@esfoliante_txt

“This is incredible. Very well done!”

FireflyDaniel

Your next Flutter app starts with one command

Free, MIT licensed, and it's still just Flutter underneath.

$ dart pub global activate nylo_installer