Skip to content
Back to skills

Performance

ASecurity

> **MIGRATED:** SSOT now lives in `better-toolkits/toolkits/assurance-toolkit/skills/flutter-performance/` + `references/testing/protocol.md`. This copy is a shim.

  • 4 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 8, 2026
devopsgobashtestingperformance

Works with

  • cli

Security analysis

A100/100

Scanned November 10, 2026

npx -y skills add chimeranext/flutter-boilerplate-monorepo-template --skill performance --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Performance?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Performance
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/chimeranext-performance/badge)](https://www.skillsdirectory.com/skills/chimeranext-performance)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
> **MIGRATED:** SSOT now lives in `better-toolkits/toolkits/assurance-toolkit/skills/flutter-performance/` + `references/testing/protocol.md`. This copy is a shim.

# ⚡ Skill: Performance Optimization

## 📋 Metadata

| Atributo | Valor |
|----------|-------|
| **ID** | `flutter-performance` |
| **Nivel** | 🔴 Avanzado |
| **Versión** | 1.0.0 |
| **Keywords** | `performance`, `optimization`, `profiling`, `memory`, `rendering` |
| **Referencia** | [Flutter Performance Best Practices](https://docs.flutter.dev/perf/best-practices) |

## 🔑 Keywords para Invocación

- `performance`
- `optimization`
- `profiling`
- `memory-leak`
- `rendering-optimization`
- `@skill:performance`

### Ejemplos de Prompts

```
Optimiza el performance de la app
```

```
Reduce el rebuild y mejora el rendering
```

```
@skill:performance - Implementa mejores prácticas de performance
```

## 📖 Descripción

Performance Optimization cubre técnicas para mejorar velocidad, fluidez y eficiencia de apps Flutter: reducir rebuilds, optimizar listas, gestión de memoria, lazy loading, code splitting, image optimization y profiling.

**⚠️ IMPORTANTE:** Todos los comandos de este skill deben ejecutarse desde la **raíz del proyecto** (donde existe el directorio `mobile/`). El skill incluye verificaciones para asegurar que se está en el directorio correcto antes de ejecutar cualquier comando.

**⚠️ IMPORTANTE:** Todos los comandos de este skill deben ejecutarse desde la **raíz del proyecto** (donde existe el directorio `mobile/`). El skill incluye verificaciones para asegurar que se está en el directorio correcto antes de ejecutar cualquier comando.

### ✅ Cuándo Usar Este Skill

- App tiene lag o stuttering
- Tiempos de carga lentos
- Consumo excesivo de memoria
- Frame drops en animaciones
- Listas largas con scrolling lento
- Build times largos

### ❌ Cuándo NO Usar Este Skill

- Premature optimization en prototipos
- Performance ya es aceptable

## 🏗️ Estructura del Proyecto

```
lib/
├── core/
│   ├── performance/
│   │   ├── performance_monitor.dart
│   │   ├── memory_tracker.dart
│   │   └── build_tracker.dart
│   └── widgets/
│       ├── optimized/
│       │   ├── optimized_list_view.dart
│       │   ├── cached_network_image_wrapper.dart
│       │   └── sliver_performance_widget.dart
│       └── lazy/
│           └── lazy_indexed_stack.dart
└── main.dart
```

## 📦 Dependencias Requeridas

```yaml
dependencies:
  flutter:
    sdk: flutter

  # Image optimization
  cached_network_image: ^3.3.0
  flutter_cache_manager: ^3.3.1

  # Performance monitoring
  performance: ^0.2.0

  # Utils
  equatable: ^2.0.5

dev_dependencies:
  # Performance testing
  integration_test:
    sdk: flutter
  flutter_driver:
    sdk: flutter
```

## 💻 Implementación

### 1. Reducir Rebuilds con const

```dart
// ❌ BAD: Widget se reconstruye en cada frame
class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text('Hello'),
    );
  }
}

// ✅ GOOD: Widget es const, no se reconstruye
class MyWidget extends StatelessWidget {
  const MyWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return const Text('Hello');
  }
}
```

### 2. Usar Keys Correctamente

```dart
// ✅ GOOD: ValueKey para identificar widgets únicamente
ListView.builder(
  itemCount: items.length,
  itemBuilder: (context, index) {
    final item = items[index];
    return ItemWidget(
      key: ValueKey(item.id),  // Ayuda a Flutter a identificar el widget
      item: item,
    );
  },
)
```

### 3. Optimizar ListView con ListView.builder

```dart
// ❌ BAD: Crea todos los widgets a la vez
ListView(
  children: items.map((item) => ItemWidget(item: item)).toList(),
)

// ✅ GOOD: Crea widgets solo cuando son visibles
ListView.builder(
  itemCount: items.length,
  itemBuilder: (context, index) {
    return ItemWidget(item: items[index]);
  },
)

// ✅ BETTER: Con separadores eficientes
ListView.separated(
  itemCount: items.length,
  itemBuilder: (context, index) => ItemWidget(item: items[index]),
  separatorBuilder: (context, index) => const Divider(height: 1),
)
```

### 4. Usar RepaintBoundary

```dart
// Aislar widgets que se repintan frecuentemente
class AnimatedWidget extends StatefulWidget {
  @override
  _AnimatedWidgetState createState() => _AnimatedWidgetState();
}

class _AnimatedWidgetState extends State<AnimatedWidget>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 2),
    )..repeat();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        // Widget estático, no necesita repaint
        const Text('Static Header'),

        // Widget animado, aislado con RepaintBoundary
        RepaintBoundary(
          child: AnimatedBuilder(
            animation: _controller,
            builder: (context, child) {
              return Transform.rotate(
                angle: _controller.value * 2 * 3.14159,
                child: child,
              );
            },
            child: const Icon(Icons.refresh, size: 100),
          ),
        ),

        // Otro widget estático
        const Text('Static Footer'),
      ],
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
}
```

### 5. Optimizar Imágenes

```dart
// lib/core/widgets/optimized/optimized_image.dart
import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';

class OptimizedImage extends StatelessWidget {
  final String imageUrl;
  final double? width;
  final double? height;
  final BoxFit fit;

  const OptimizedImage({
    super.key,
    required this.imageUrl,
    this.width,
    this.height,
    this.fit = BoxFit.cover,
  });

  @override
  Widget build(BuildContext context) {
    return CachedNetworkImage(
      imageUrl: imageUrl,
      width: width,
      height: height,
      fit: fit,

      // Progressive loading
      progressIndicatorBuilder: (context, url, downloadProgress) {
        return Center(
          child: CircularProgressIndicator(
            value: downloadProgress.progress,
          ),
        );
      },

      // Error handling
      errorWidget: (context, url, error) {
        return const Icon(Icons.error);
      },

      // Memory cache
      memCacheWidth: width?.toInt(),
      memCacheHeight: height?.toInt(),

      // Fade in animation
      fadeInDuration: const Duration(milliseconds: 300),
    );
  }
}

// Uso
OptimizedImage(
  imageUrl: 'https://example.com/image.jpg',
  width: 100,
  height: 100,
  fit: BoxFit.cover,
)
```

### 6. Lazy Loading con AutomaticKeepAliveClientMixin

```dart
// Mantener estado de tabs sin reconstruir
class ProductsTab extends StatefulWidget {
  const ProductsTab({super.key});

  @override
  State<ProductsTab> createState() => _ProductsTabState();
}

class _ProductsTabState extends State<ProductsTab>
    with AutomaticKeepAliveClientMixin {
  @override
  bool get wantKeepAlive => true;  // Mantener estado

  @override
  Widget build(BuildContext context) {
    super.build(context);  // IMPORTANTE: Llamar super.build

    return ListView.builder(
      itemCount: 100,
      itemBuilder: (context, index) {
        return ListTile(title: Text('Product $index'));
      },
    );
  }
}
```

### 7. Optimizar Slivers

```dart
class OptimizedScrollView extends StatelessWidget {
  const OptimizedScrollView({super.key});

  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
      slivers: [
        // App bar que se colapsa
        SliverAppBar(
          expandedHeight: 200,
          pinned: true,
          flexibleSpace: FlexibleSpaceBar(
            title: const Text('Products'),
            background: Image.network(
              'https://example.com/header.jpg',
              fit: BoxFit.cover,
            ),
          ),
        ),

        // Lista optimizada con builder
        SliverList(
          delegate: SliverChildBuilderDelegate(
            (context, index) {
              return ProductCard(index: index);
            },
            childCount: 1000,
          ),
        ),

        // Grid optimizado
        SliverGrid(
          gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 2,
            mainAxisSpacing: 10,
            crossAxisSpacing: 10,
          ),
          delegate: SliverChildBuilderDelegate(
            (context, index) {
              return GridItem(index: index);
            },
            childCount: 100,
          ),
        ),
      ],
    );
  }
}
```

### 8. Evitar Funciones en build()

```dart
// ❌ BAD: Función se ejecuta en cada build
class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Text(
      _formatDate(DateTime.now()),  // Se calcula en cada build
      style: _getTextStyle(),        // Se crea en cada build
    );
  }

  String _formatDate(DateTime date) {
    return '${date.day}/${date.month}/${date.year}';
  }

  TextStyle _getTextStyle() {
    return const TextStyle(fontSize: 16, fontWeight: FontWeight.bold);
  }
}

// ✅ GOOD: Valores se calculan una vez
class MyWidget extends StatelessWidget {
  final String formattedDate;
  static const textStyle = TextStyle(fontSize: 16, fontWeight: FontWeight.bold);

  MyWidget({super.key}) : formattedDate = _formatDate(DateTime.now());

  static String _formatDate(DateTime date) {
    return '${date.day}/${date.month}/${date.year}';
  }

  @override
  Widget build(BuildContext context) {
    return Text(formattedDate, style: textStyle);
  }
}
```

### 9. Usar Selector para Actualizaciones Específicas

```dart
// Con flutter_bloc
class ProductPriceText extends StatelessWidget {
  const ProductPriceText({super.key});

  @override
  Widget build(BuildContext context) {
    // Solo se reconstruye cuando el precio cambia
    final price = context.select((ProductBloc bloc) => bloc.state.price);

    return Text('\$$price');
  }
}

// Con Provider
class ProductPriceText extends StatelessWidget {
  const ProductPriceText({super.key});

  @override
  Widget build(BuildContext context) {
    // Solo se reconstruye cuando el precio cambia
    final price = context.select<ProductModel, double>((product) => product.price);

    return Text('\$$price');
  }
}
```

### 10. Lazy IndexedStack

```dart
// lib/core/widgets/lazy/lazy_indexed_stack.dart
class LazyIndexedStack extends StatefulWidget {
  final int index;
  final List<Widget> children;

  const LazyIndexedStack({
    super.key,
    required this.index,
    required this.children,
  });

  @override
  State<LazyIndexedStack> createState() => _LazyIndexedStackState();
}

class _LazyIndexedStackState extends State<LazyIndexedStack> {
  late List<bool> _activated;

  @override
  void initState() {
    super.initState();
    _activated = List.generate(widget.children.length, (i) => i == widget.index);
  }

  @override
  void didUpdateWidget(LazyIndexedStack oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.index != widget.index) {
      _activated[widget.index] = true;
    }
  }

  @override
  Widget build(BuildContext context) {
    return IndexedStack(
      index: widget.index,
      children: List.generate(
        widget.children.length,
        (i) => _activated[i] ? widget.children[i] : const SizedBox.shrink(),
      ),
    );
  }
}
```

### 11. Performance Monitoring

```dart
// lib/core/performance/performance_monitor.dart
import 'package:flutter/scheduler.dart';

class PerformanceMonitor {
  static void trackBuildTime(String widgetName, VoidCallback buildFunction) {
    final stopwatch = Stopwatch()..start();

    buildFunction();

    stopwatch.stop();

    if (stopwatch.elapsedMilliseconds > 16) {  // 60 FPS = 16ms per frame
      print('⚠️ Slow build: $widgetName took ${stopwatch.elapsedMilliseconds}ms');
    }
  }

  static void trackFrameTime() {
    SchedulerBinding.instance.addTimingsCallback((timings) {
      for (final timing in timings) {
        final buildTime = timing.buildDuration.inMilliseconds;
        final rasterTime = timing.rasterDuration.inMilliseconds;

        if (buildTime > 16 || rasterTime > 16) {
          print('⚠️ Frame drop: Build=${buildTime}ms, Raster=${rasterTime}ms');
        }
      }
    });
  }
}

// Uso
class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return PerformanceMonitor.trackBuildTime('MyWidget', () {
      return Container(
        // widget content
      );
    }) as Widget;
  }
}
```

### 12. Code Splitting con Deferred Loading

```dart
// lib/features/settings/settings.dart
library settings;

export 'presentation/screens/settings_screen.dart';
export 'presentation/widgets/settings_list.dart';

// main.dart
import 'features/settings/settings.dart' deferred as settings;

// Cargar módulo cuando sea necesario
void navigateToSettings() async {
  await settings.loadLibrary();  // Carga el código
  Navigator.push(
    context,
    MaterialPageRoute(builder: (_) => settings.SettingsScreen()),
  );
}
```

## 🎯 Mejores Prácticas

### 1. Profiling con DevTools

```bash
# Abrir Flutter DevTools
flutter pub global activate devtools
flutter pub global run devtools

# Verificar que estamos en la raíz del proyecto
if [ ! -d "mobile" ]; then
    echo "Error: Ejecuta este comando desde la raíz del proyecto"
    exit 1
fi

# Ejecutar app en profile mode
cd mobile
flutter run --profile
cd ..

# Performance overlay en código
void main() {
  runApp(MyApp());

  if (kProfileMode) {
    WidgetsApp.debugShowWidgetInspector = true;
  }
}
```

### 2. Build Mode Correcto

```bash
# Verificar que estamos en la raíz del proyecto
if [ ! -d "mobile" ]; then
    echo "Error: Ejecuta este comando desde la raíz del proyecto"
    exit 1
fi

# Debug (desarrollo) - Sin optimizaciones
cd mobile
flutter run
cd ..

# Profile (testing performance) - Optimizado pero con DevTools
cd mobile
flutter run --profile
cd ..

# Release (producción) - Totalmente optimizado
cd mobile
flutter run --release
cd ..
```

### 3. Avoid Doing Work in Build

```dart
// ❌ BAD
class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Cálculos pesados aquí
    final expensiveData = _performExpensiveCalculation();
    return Text(expensiveData);
  }
}

// ✅ GOOD
class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  late String _cachedData;

  @override
  void initState() {
    super.initState();
    _cachedData = _performExpensiveCalculation();
  }

  @override
  Widget build(BuildContext context) {
    return Text(_cachedData);
  }
}
```

### 4. Dispose Correctly

```dart
class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  late AnimationController _controller;
  late StreamSubscription _subscription;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this);
    _subscription = someStream.listen((_) {});
  }

  @override
  void dispose() {
    _controller.dispose();  // ✅ Siempre dispose
    _subscription.cancel(); // ✅ Siempre cancel
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}
```

## 📊 Performance Checklist

- [ ] Usar `const` constructors donde sea posible
- [ ] ListView.builder en lugar de ListView con children
- [ ] RepaintBoundary para widgets que se repintan frecuentemente
- [ ] Imágenes optimizadas y cacheadas
- [ ] Dispose de controllers, streams y subscriptions
- [ ] Lazy loading de tabs con AutomaticKeepAliveClientMixin
- [ ] Keys apropiadas en listas
- [ ] Evitar funciones anónimas en build()
- [ ] Code splitting con deferred loading
- [ ] Profiling regular con DevTools

## 📚 Recursos Adicionales

- [Flutter Performance Best Practices](https://docs.flutter.dev/perf/best-practices)
- [Flutter DevTools](https://docs.flutter.dev/development/tools/devtools/overview)
- [Performance Profiling](https://docs.flutter.dev/perf/rendering/ui-performance)

## 🔗 Skills Relacionados

- [Clean Architecture](../clean-architecture/SKILL.md)
- [Testing Strategy](../testing/SKILL.md)

---

**Versión:** 1.0.0
**Última actualización:** Diciembre 2025

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

View all in devops →

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.