Getting Started

Upgrade Guide

What's New in v7

Nylo Website v7 is a major release with significant improvements to the developer experience:

Encrypted Environment Configuration

  • Environment variables are now XOR-encrypted at build time for security
  • New metro make:key generates your APP_KEY
  • New metro make:env generates encrypted env.g.dart
  • Support for --dart-define APP_KEY injection for CI/CD pipelines

Simplified Boot Process

  • New BootConfig pattern replaces separate setup/finished callbacks
  • Cleaner Nylo.init() with env parameter for encrypted environment
  • App lifecycle hooks directly in main.dart

New nylo.configure() API

  • Single method consolidates all app configuration
  • Cleaner syntax replaces individual nylo.add*() calls
  • Separate setup() and boot() lifecycle methods in providers

NyPage for Pages

  • NyPage replaces NyState for page widgets (cleaner syntax)
  • view() replaces build() method
  • get init => getter replaces init() and boot() methods
  • NyState is still available for non-page stateful widgets

LoadingStyle System

  • New LoadingStyle enum for consistent loading states
  • Options: LoadingStyle.normal(), LoadingStyle.skeletonizer(), LoadingStyle.none()
  • Custom loading widgets via LoadingStyle.normal(child: ...)

RouteView Type-Safe Routing

  • static RouteView path replaces static const path
  • Type-safe route definitions with widget factory

Multi-Theme Support

  • Register multiple dark and light themes
  • Theme IDs defined in code instead of .env file
  • New NyThemeType.dark / NyThemeType.light for theme classification
  • Preferred theme API: NyTheme.setPreferredDark(), NyTheme.setPreferredLight()
  • Theme enumeration: NyTheme.lightThemes(), NyTheme.darkThemes(), NyTheme.all()

New Metro Commands

  • make:key - Generate APP_KEY for encryption
  • make:env - Generate encrypted environment file
  • make:bottom_sheet_modal - Create bottom sheet modals
  • make:button - Create custom buttons

View all changes on GitHub

Breaking Changes Overview

Change v6 v7
App Root Widget LocalizedApp(child: Main(nylo)) Main(nylo) (uses NyApp.materialApp())
Page State Class NyState NyPage for pages
View Method build() view()
Init Method init() async {} / boot() async {} get init => () async {}
Route Path static const path = '/home' static RouteView path = ('/home', (_) => HomePage())
Provider Boot boot(Nylo nylo) setup(Nylo nylo) + boot(Nylo nylo)
Configuration Individual nylo.add*() calls Single nylo.configure() call
Theme IDs .env file (LIGHT_THEME_ID, DARK_THEME_ID) Code (type: NyThemeType.dark)
Loading Widget useSkeletonizer + loading() LoadingStyle getter
Config Location lib/config/ lib/bootstrap/ (decoders, events, providers, theme)
Asset Location public/ assets/

Recommended Migration Approach

For larger projects, we recommend creating a fresh v7 project and migrating files:

  1. Create new v7 project: git clone https://github.com/nylo-core/nylo.git my_app_v7 -b 7.x
  2. Copy your pages, controllers, models, and services
  3. Update syntax as shown above
  4. Test thoroughly

This ensures you have all the latest boilerplate structure and configurations.

If you are interested in seeing a diff of the changes between v6 and v7, you can view the comparison on GitHub: https://github.com/nylo-core/nylo/compare/6.x...7.x

Quick Migration Checklist

Use this checklist to track your migration progress:

  • Update pubspec.yaml (Dart >=3.10.7, Flutter >=3.24.0, nylo_framework: ^7.0.0)
  • Run flutter pub get
  • Run metro make:key to generate APP_KEY
  • Run metro make:env to generate encrypted environment
  • Update main.dart with env parameter and BootConfig
  • Convert Boot class to use BootConfig pattern
  • Move config files from lib/config/ to lib/bootstrap/
  • Create new config files (lib/config/app.dart, lib/config/storage_keys.dart, lib/config/toast_notification.dart)
  • Update AppProvider to use nylo.configure()
  • Remove LIGHT_THEME_ID and DARK_THEME_ID from .env
  • Add type: NyThemeType.dark to dark theme configurations
  • Rename NyState to NyPage for all page widgets
  • Change build() to view() in all pages
  • Change init()/boot() to get init => in all pages
  • Update static const path to static RouteView path
  • Change router.route() to router.add() in routes
  • Rename widgets (NyListView → CollectionView, etc.)
  • Move assets from public/ to assets/
  • Update pubspec.yaml asset paths
  • Remove Firebase imports (if using - add packages directly)
  • Remove NyDevPanel usage (use Flutter DevTools)
  • Run flutter pub get and test

Step-by-Step Migration Guide

Step 1: Update Dependencies

Update your pubspec.yaml:

environment:
  sdk: '>=3.10.7 <4.0.0'
  flutter: ">=3.24.0"

dependencies:
  nylo_framework: ^7.0.0
  # ... other dependencies

Run flutter pub get to update packages.

Step 2: Environment Configuration

v7 requires encrypted environment variables for improved security.

1. Generate APP_KEY:

metro make:key

This adds APP_KEY to your .env file.

2. Generate encrypted env.g.dart:

metro make:env

This creates lib/bootstrap/env.g.dart containing your encrypted environment variables.

3. Remove deprecated theme variables from .env:

# Remove these lines from your .env file:
LIGHT_THEME_ID=...
DARK_THEME_ID=...

Step 3: Update main.dart

v6:

import 'package:nylo_framework/nylo_framework.dart';
import 'bootstrap/boot.dart';

void main() async {
  await Nylo.init(
    setup: Boot.nylo,
    setupFinished: Boot.finished,
  );
}

v7:

import '/bootstrap/env.g.dart';
import 'package:nylo_framework/nylo_framework.dart';
import 'bootstrap/boot.dart';

void main() async {
  await Nylo.init(
    env: Env.get,
    setup: Boot.nylo(),
    appLifecycle: {
      // Optional: Add app lifecycle hooks
      // AppLifecycleState.resumed: () => print("App resumed"),
      // AppLifecycleState.paused: () => print("App paused"),
    },
  );
}

Key Changes:

  • Import the generated env.g.dart
  • Pass Env.get to the env parameter
  • Boot.nylo is now Boot.nylo() (returns BootConfig)
  • setupFinished is removed (handled within BootConfig)
  • Optional appLifecycle hooks for app state changes

Step 4: Update boot.dart

v6:

class Boot {
  static Future<Nylo> nylo() async {
    WidgetsFlutterBinding.ensureInitialized();

    if (getEnv('SHOW_SPLASH_SCREEN', defaultValue: false)) {
      runApp(SplashScreen.app());
    }

    await _setup();
    return await bootApplication(providers);
  }

  static Future<void> finished(Nylo nylo) async {
    await bootFinished(nylo, providers);
    runApp(Main(nylo));
  }
}

v7:

class Boot {
  static BootConfig nylo() => BootConfig(
        setup: () async {
          WidgetsFlutterBinding.ensureInitialized();

          if (AppConfig.showSplashScreen) {
            runApp(SplashScreen.app());
          }

          await _init();
          return await setupApplication(providers);
        },
        boot: (Nylo nylo) async {
          await bootFinished(nylo, providers);
          runApp(Main(nylo));
        },
      );
}

Key Changes:

  • Returns BootConfig instead of Future<Nylo>
  • setup and finished combined into single BootConfig object
  • getEnv('SHOW_SPLASH_SCREEN')AppConfig.showSplashScreen
  • bootApplicationsetupApplication

Step 5: Reorganize Configuration Files

v7 reorganizes configuration files for better structure:

v6 Location v7 Location Action
lib/config/decoders.dart lib/bootstrap/decoders.dart Move
lib/config/events.dart lib/bootstrap/events.dart Move
lib/config/providers.dart lib/bootstrap/providers.dart Move
lib/config/theme.dart lib/bootstrap/theme.dart Move
lib/config/keys.dart lib/config/storage_keys.dart Rename & Refactor
(new) lib/config/app.dart Create
(new) lib/config/toast_notification.dart Create

Create lib/config/app.dart:

Reference: App Config

class AppConfig {
  // The name of the application.
  static final String appName = getEnv('APP_NAME', defaultValue: 'Nylo');

  // The version of the application.
  static final String version = getEnv('APP_VERSION', defaultValue: '1.0.0');
  
  // Add other app configuration here
}

Create lib/config/storage_keys.dart:

Reference: Storage Keys

final class StorageKeysConfig {
  // Define the keys you want to be synced on boot
  static syncedOnBoot() => () async {
        return [
          auth,
          bearerToken,
          // coins.defaultValue(10), // give the user 10 coins by default
        ];
      };

  static StorageKey auth = 'SK_USER';

  static StorageKey bearerToken = 'SK_BEARER_TOKEN';

  // static StorageKey coins = 'SK_COINS';

  /// Add your storage keys here...
}

Create lib/config/toast_notification.dart:

Reference: Toast Notification Config

import 'package:nylo_framework/nylo_framework.dart';

class ToastNotificationConfig {
  static Map<ToastNotificationStyleMetaHelper, ToastMeta> styles = {
    // Customize toast styles here
  };
}

Step 6: Update AppProvider

v6:

class AppProvider implements NyProvider {
  @override
  boot(Nylo nylo) async {
    await NyLocalization.instance.init(
      localeType: localeType,
      languageCode: languageCode,
      assetsDirectory: assetsDirectory,
    );

    nylo.addLoader(loader);
    nylo.addLogo(logo);
    nylo.addThemes(appThemes);
    nylo.addToastNotification(getToastNotificationWidget);
    nylo.addValidationRules(validationRules);
    nylo.addModelDecoders(modelDecoders);
    nylo.addControllers(controllers);
    nylo.addApiDecoders(apiDecoders);
    nylo.useErrorStack();
    nylo.addAuthKey(Keys.auth);
    await nylo.syncKeys(Keys.syncedOnBoot);

    return nylo;
  }

  @override
  afterBoot(Nylo nylo) async {}
}

v7:

class AppProvider implements NyProvider {
  @override
  setup(Nylo nylo) async {
    await nylo.configure(
      localization: NyLocalizationConfig(
        languageCode: LocalizationConfig.languageCode,
        localeType: LocalizationConfig.localeType,
        assetsDirectory: LocalizationConfig.assetsDirectory,
      ),
      loader: DesignConfig.loader,
      logo: DesignConfig.logo,
      themes: appThemes,
      initialThemeId: 'light_theme',
      toastNotifications: ToastNotificationConfig.styles,
      modelDecoders: modelDecoders,
      controllers: controllers,
      apiDecoders: apiDecoders,
      authKey: StorageKeysConfig.auth,
      syncKeys: StorageKeysConfig.syncedOnBoot,
      useErrorStack: true,
    );

    return nylo;
  }

  @override
  boot(Nylo nylo) async {}
}

Key Changes:

  • boot() is now setup() for initial configuration
  • boot() is now used for post-setup logic (previously afterBoot)
  • All nylo.add*() calls consolidated into single nylo.configure()
  • Localization uses NyLocalizationConfig object

Step 7: Update Theme Configuration

v6 (.env file):

LIGHT_THEME_ID=default_light_theme
DARK_THEME_ID=default_dark_theme

v6 (theme.dart):

final List<BaseThemeConfig> appThemes = [
  BaseThemeConfig(
    id: getEnv('LIGHT_THEME_ID'),
    description: "Light Theme",
    theme: lightTheme(),
    colors: LightThemeColors(),
  ),
  BaseThemeConfig(
    id: getEnv('DARK_THEME_ID'),
    description: "Dark Theme",
    theme: darkTheme(),
    colors: DarkThemeColors(),
  ),
];

v7 (theme.dart):

final List<BaseThemeConfig<ColorStyles>> appThemes = [
  BaseThemeConfig<ColorStyles>(
    id: 'light_theme',
    theme: lightTheme,
    colors: LightThemeColors(),
    type: NyThemeType.light,
  ),
  BaseThemeConfig<ColorStyles>(
    id: 'dark_theme',
    theme: darkTheme,
    colors: DarkThemeColors(),
    type: NyThemeType.dark,
  ),
];

Key Changes:

  • Remove LIGHT_THEME_ID and DARK_THEME_ID from .env
  • Define theme IDs directly in code
  • Add type: NyThemeType.dark to all dark theme configurations
  • Light themes default to NyThemeType.light

New Theme API Methods (v7):

// Set and remember preferred theme
NyTheme.set(context, id: 'dark_theme', remember: true);

// Set preferred themes for system following
NyTheme.setPreferredDark('dark_theme');
NyTheme.setPreferredLight('light_theme');

// Get preferred theme IDs
String? darkId = NyTheme.preferredDarkId();
String? lightId = NyTheme.preferredLightId();

// Theme enumeration
List<BaseThemeConfig> lights = NyTheme.lightThemes();
List<BaseThemeConfig> darks = NyTheme.darkThemes();
List<BaseThemeConfig> all = NyTheme.all();
BaseThemeConfig? theme = NyTheme.getById('dark_theme');
List<BaseThemeConfig> byType = NyTheme.getByType(NyThemeType.dark);

// Clear saved preferences
NyTheme.clearSavedTheme();

Step 10: Migrate Widgets

NyListView → CollectionView

v6:

NyListView(
  child: (context, data) {
    return ListTile(title: Text(data.name));
  },
  data: () async => await api.getUsers(),
  loading: CircularProgressIndicator(),
)

v7:

CollectionView<User>(
  data: () async => await api.getUsers(),
  builder: (context, item) => ListTile(
    title: Text(item.data.name),
  ),
  loadingStyle: LoadingStyle.normal(),
)

// With pagination (pull to refresh):
CollectionView<User>.pullable(
  data: (page) async => await api.getUsers(page: page),
  builder: (context, item) => ListTile(
    title: Text(item.data.name),
  ),
)

NyFutureBuilder → FutureWidget

v6:

NyFutureBuilder(
  future: fetchData(),
  child: (context, data) => Text(data),
  loading: CircularProgressIndicator(),
)

v7:

FutureWidget<String>(
  future: fetchData(),
  child: (context, data) => Text(data ?? ''),
  loadingStyle: LoadingStyle.normal(),
)

NyTextField → InputField

v6:

NyTextField(
  controller: _controller,
  validationRules: "not_empty|email",
)

v7:

InputField(
  controller: _controller,
  formValidator: FormValidator
                  .notEmpty()
                  .email(),
),

NyRichText → StyledText

v6:

NyRichText(children: [
	Text("Hello", style: TextStyle(color: Colors.yellow)),
	Text(" WORLD ", style: TextStyle(color: Colors.blue)),
	Text("!", style: TextStyle(color: Colors.red)),
]),

v7:

StyledText.template(
  "{{Hello}} {{WORLD}}{{!}}",
  styles: {
    "Hello": TextStyle(color: Colors.yellow),
    "WORLD": TextStyle(color: Colors.blue),
    "!": TextStyle(color: Colors.red),
  },
)

NyLanguageSwitcher → LanguageSwitcher

v6:

NyLanguageSwitcher(
  onLanguageChange: (locale) => print(locale),
)

v7:

LanguageSwitcher(
  onLanguageChange: (locale) => print(locale),
)

Step 11: Update Asset Paths

v7 changes the asset directory from public/ to assets/:

1. Move your asset folders:

# Move directories
mv public/fonts assets/fonts
mv public/images assets/images
mv public/app_icon assets/app_icon

2. Update pubspec.yaml:

v6:

flutter:
  assets:
    - public/fonts/
    - public/images/
    - public/app_icon/

v7:

flutter:
  assets:
    - assets/fonts/
    - assets/images/
    - assets/app_icon/

3. Update any asset references in code:

v6:

Image.asset('public/images/logo.png')

v7:

Image.asset('assets/images/logo.png')

LocalizedApp Widget - Removed

Reference: Main Widget

Migration: Use Main(nylo) directly. The NyApp.materialApp() handles localization internally.

v6:

runApp(LocalizedApp(child: Main(nylo)));

v7:

runApp(Main(nylo));

Deleted Classes Reference

Deleted Class Alternative
NyTextStyle Use Flutter's TextStyle directly
NyBaseApiService Use DioApiService
BaseColorStyles Use ThemeColor
LocalizedApp Use Main(nylo) directly
NyException Use standard Dart exceptions
PushNotification Use flutter_local_notifications directly
PushNotificationAttachments Use flutter_local_notifications directly

Widget Migration Reference

Renamed Widgets

v6 Widget v7 Widget Notes
NyListView CollectionView New API with builder instead of child
NyFutureBuilder FutureWidget Simplified async widget
NyTextField InputField Uses FormValidator
NyLanguageSwitcher LanguageSwitcher Same API
NyRichText StyledText Same API
NyFader FadeOverlay Same API

Deleted Widgets (No Direct Replacement)

Deleted Widget Alternative
NyPullToRefresh Use CollectionView.pullable()

Widget Migration Examples

NyPullToRefresh → CollectionView.pullable():

v6:

NyPullToRefresh(
  child: (context, data) => ListTile(title: Text(data.name)),
  data: (page) async => await fetchData(page),
)

v7:

CollectionView<MyModel>.pullable(
  data: (page) async => await fetchData(page),
  builder: (context, item) => ListTile(title: Text(item.data.name)),
)

NyFader → AnimatedOpacity:

v6:

NyFader(
  child: MyWidget(),
)

v7:

FadeOverlay.bottom(
  child: MyWidget(),
);

Troubleshooting

"Env.get not found" or "Env is not defined"

Solution: Run the environment generation commands:

metro make:key
metro make:env

Then import the generated file in main.dart:

import '/bootstrap/env.g.dart';

"Theme not applying" or "Dark theme not working"

Solution: Ensure dark themes have type: NyThemeType.dark:

BaseThemeConfig(
  id: 'dark_theme',
  description: "Dark Theme",
  theme: darkTheme(),
  colors: DarkThemeColors(),
  type: NyThemeType.dark, // Add this line
),

"LocalizedApp not found"

Reference: Main Widget

Solution: LocalizedApp has been removed. Change:

// From:
runApp(LocalizedApp(child: Main(nylo)));

// To:
runApp(Main(nylo));

"router.route is not defined"

Solution: Use router.add() instead:

// From:
router.route(HomePage.path, (context) => HomePage());

// To:
router.add(HomePage.path);

"NyListView not found"

Solution: NyListView is now CollectionView:

// From:
NyListView(...)

// To:
CollectionView<MyModel>(...)

Assets not loading (images, fonts)

Solution: Update asset paths from public/ to assets/:

  1. Move files: mv public/* assets/
  2. Update pubspec.yaml paths
  3. Update code references

"init() must return a value of type Future"

Solution: Change to the getter syntax:

// From:
@override
init() async { ... }

// To:
@override
get init => () async { ... };

Need help? Check the Nylo Documentation or open an issue on GitHub.