# ENVied: the best way to handle your environment variables in Flutter

Hi everyone, in this post, I want to show you the best way to store environment variables in a Flutter project that I started to use some months ago in all of my projects after seeing it in this blog post from CodewithAndrea: [How to Store API Keys in Flutter: --dart-define vs .env files](https://codewithandrea.com/articles/flutter-api-keys-dart-define-env-files/).

In an application that communicates with external services, that needs to authenticate via API key or to configure particular settings we must set environment variables that must be kept as hidden as possible, especially those related to API keys, but rather conveniently to be used in our Flutter applications.

For all this, we are helped by the valid [ENVied](https://pub.dev/packages/envied) package that lets you create a convenient Dart class that maps the `.env` file. To install it we can add it to the `pubspec.yaml` file along with `envied_generator` and `build_runner` for the build step and generation of the Dart class:

```yaml
dependencies:
  ...
  envied: ^0.3.0

dev_dependencies:
  ...
  envied_generator: ^0.3.0
  build_runner: ^2.3.3

```

Now we can create an `.env` file inside our project where we can add all our environment variables like this:

```makefile
GREETINGS="Hello world!"
MY_NAME="Alberto"
```

Now we have to create a `env.dart` file where we can define our constants:

```dart
import 'package:envied/envied.dart';

part 'env.g.dart';

//Here you can specify the path to your .env file
//  relative to the project root
@Envied(path: '.env')
abstract class Env {
  //The ofuscate flag lets you make your variables more
  // secure through obfuscation
  @EnviedField(varName: 'GREETINGS', obfuscate: true)
  static final greetings = _Env.greetings;
  @EnviedField(varName: 'MY_NAME', obfuscate: true)
  static final myName = _Env.myName;
}
```

Now we can do the build step and let ENVied generate the class for us, so let's run:

```bash
flutter pub run build_runner build --delete-conflicting-outputs
```

ENVied will generate a file named `env.g.dart` alongside `env.dart` with pretty much this content:

```dart
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'env.dart';
// *****************************************************
// EnviedGenerator
// *****************************************************
class _Env {
  static const List<int> _enviedkeygreetings = [
    3271495377, 3997315090, 436058207, 3553787292, 3538777736,
    955590460, 3819871908, 4039201348, 2424541315, 3686169803,
    1299522498, 1263434759
  ];
  static const List<int> _envieddatagreetings = [
    3271495321, 3997315191, 436058163, 3553787376, 3538777831,
    955590428, 3819871955, 4039201323, 2424541425, 3686169767,
    1299522470, 1263434790
  ];
  static final greetings = String.fromCharCodes(
    List.generate(_envieddatagreetings.length, (i) => i, growable: false)
        .map((i) => _envieddatagreetings[i] ^ _enviedkeygreetings[i])
        .toList(growable: false),
  );
  static const List<int> _enviedkeymyName = [
    3026637516, 1908999005, 3526437322, 2478128297, 2753058997,
    855764648, 1111676782
  ];
  static const List<int> _envieddatamyName = [
    3026637453, 1908998961, 3526437288, 2478128332, 2753059015,
    855764700, 1111676673
  ];
  static final myName = String.fromCharCodes(
    List.generate(_envieddatamyName.length, (i) => i, growable: false)
        .map((i) => _envieddatamyName[i] ^ _enviedkeymyName[i])
        .toList(growable: false),
  );
}
```

Before proceeding it is good to exclude from version control the `.env` and `env.g.dart` files that contain all our variables, to do this simply add to the `.gitignore` file:

```makefile
#Envied
*.env
env.g.dart
```

### App Code

At this point, we can create a small example app that shows how to use our environment variables and call them within the code, so create a `main.dart` file with the following code:

```dart
import 'package:flutter/material.dart';

import 'env.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'ENVied Demo',
      home: Scaffold(
        appBar: AppBar(
          title: const Text("ENVied Demo"),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(
                Env.greetings,
              ),
              Text(
                "Hi, I'm ${Env.myName}",
              ),
            ],
          ),
        ),
      ),
    );
  }
}
```

As you can see we can call within the code of our app the environment variables we created simply with:

```dart
//Import the env class
import 'env.dart';

//Use variables
Env.greetings
Env.myName
```

The result is something like this:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1673592242656/1d1e575c-3f82-4df1-823f-644b855250b6.png align="center")

### Conclusions

In this post, we saw how to secure our environment variables through obfuscation, how to exclude them from version control so they are not exposed in our repositories, and how to generate a Dart class that we can access throughout the code to conveniently use our variables. So we have all the requirements to start developing an app with a good degree of security.

Code strong, Alberto
