Using Doppler in a Flutter/Dart project?

Anyone used Doppler in a Flutter/Dart project? I’m not sure how to do it- as such I’m not sure if this is a feature request or a call for help. Thanks in advance!

Also, does Doppler ever serve secrets on a per request basis- like not at compile/build time but in-line with a request that requires a secret, it would fetch the Doppler secret first and then complete the request with the secret.

Hey Eric and welcome to the Doppler community!

While we don’t yet have a Swift SDK, you use a API to either download all the secrets for a config or request a single secret.

Are you able to describe your use case and how you’re wanting to use Doppler in your application?

Cheers,
Ryan

After some planning, I think it is actually two use cases:

  1. For non-sensitive secrets, like environment flags and publishable keys, I would like to inject secrets at compile/build time into a dart/flutter project. I don’t see a Dart/Flutter example in the docs and it isn’t obvious to me how I would do it.
  2. For sensitive secrets, I was imagining doing the above, or storing them server side and requesting them as needed but I’ve decided against this. I’m now planning on embedding the 3rd party API call in a cloud function and invoking that from my backend as I think I should avoid sensitive secrets being deployed in the native application.

Hi @ericmand!

I was looking into this yesterday a bit. I’m not super familiar with Flutter/Dart, but it seems like the only built-in way to inject environment variables at build time is via the --dart-define flag for Flutter or the --define flag with Dart. Some information I found said that you could pass multiple definitions to --dart-define like this: --dart-define=FOO=a,BAR=b,BAZ=c, but I wasn’t able to get that working. As such, it doesn’t appear as if there’s an easy way to simply pass environment variables in directly at command execution without a wrapper script.

That said, you can use a wrapper script like this to accomplish it:

#!/usr/bin/env bash

cmd="flutter run"

for secret in $(doppler secrets download --no-file --format env-no-quotes); do
  cmd="${cmd} --dart-define=${secret}"
done

eval $cmd

Once you’re passing in the variables, you can do something like this:

class EnvironmentConfig {
  static const DOPPLER_PROJECT = String.fromEnvironment('DOPPLER_PROJECT', defaultValue: 'unknown');
  static const FOO = String.fromEnvironment('FOO', defaultValue: 'unknown');
  static const BAR = String.fromEnvironment('BAR', defaultValue: 'unknown');
}

At that point, you can reference it using EnvironmentConfig.DOPPLER_PROJECT.

I’m certainly not an expert in this area, so it’s possible that there are better ways to do this (maybe @ryan-blunden has some ideas), but this does seem to work in the small amount of testing I was able to do.

For reference, here’s the articles I found that described this pattern:

It’s a bit dated, but has updates over time as new versions of Flutter came out. It may contain some other information that you find useful!

One other thing to keep in mind when designing your application is that Doppler does have an API rate limit described here. When the Doppler CLI fetches secrets as in the command above, that will count toward the API limit. If you were to use our API directly to fetch individual secrets on a per-request or per-client basis, then that will count toward the rate limit as well.

Let me know if the above proves useful for you!

Thanks @watsonian. This is very helpful. The only thing I don’t love about the wrapper is that I’m limited in how I can adjust the flutter build command (I think). Also, my CI system (codemagic) has a baked-in flutter build command that I can’t wrap- but does support executing scripts prior to build. Perhaps I can adjust this wrapper to assemble the dart-defines and secrets in advance and then pass them to a separately executed build command. I was imagining just exporting a bash variable with the full string of dart-defines. Not sure if that’ll work. Then for local, I’ll use a VSCode launch configuration to execute the pre-launch task to fetch the secrets and in CI I’ll execute that pre-build script option I mentioned. Does this make sense?

Yeah, I think that makes sense based on my limited knowledge around it. Regarding VS Code launch configs – I recommend checking out this thread as it contains some relevant info. I think there was/is a bug with flutter that you might hit. The user in that thread links to some GitHub issues they opened regarding them. Let me know how it goes! If a generally usable pattern can be found we’d love to get that in our documentation!

@watsonian ,
@ryan-blunden

Your wrapper “–dart-define” script is actually turned out the hardcoded $secret value on released binary.

when we compile our app, the keys are still going to be baked in in the release binary. So the people they still can deengineering your binary and find the code some where, just the matter of time.

Ref : How to Store API Keys in Flutter: --dart-define vs .env files

Ref: dart - Are compile-time variables secure in flutter? - Stack Overflow

@woon_minika Good call out! One thing that may make this easier to work with is that you can now mount Doppler secrets using the --mount flag with doppler run like this:

doppler run --mount .env -p PROJECT_NAME -c CONFIG_NAME -- YOUR_COMMAND_HERE

That will temporarily create a file called .env that’s a named pipe that functions exactly like a file, so when your app tries to read it, a request to Doppler is made under the hood and the contents are returned in env file format. You can adjust the format with --mount-format and there are a few other options you can find if you run doppler run --help and look for flags starting with --mount. This should allow you to use libraries or other methods that use .env files. It sounds like that was a recommended alternative in one of your links, so maybe this is an avenue worth pursuing!