Flutter imports: relative path or package?
Asked Answered
H

8

116

In Flutter, for importing libraries within our own package's lib directory, should we use relative imports

import 'foo.dart'

or package import?

import 'package:my_app/lib/src/foo.dart'

Dart guidelines advocate to use relative imports :

PREFER relative paths when importing libraries within your own package’s lib directory.

whereas Provider package says to always use packages imports :

  • Always use package imports. Ex: import 'package:my_app/my_code.dart';

Is there a difference other than conciseness? Why would packages imports would reduce errors over relative imports?

Heeled answered 11/1, 2020 at 9:34 Comment(0)
H
49

TLDR; Choose the one you prefer, note that prefer_relative_imports is recommended in official Effective Dart guide

First of all, as mentioned in this answer, Provider do not recommands package imports anymore.

Dart linter provides a list of rules, including some predefined rulesets :

Imports rules

There is actually more than two opposites rules concerning imports :

  • avoid_relative_lib_imports, enabled in pedantic and lints rulesets, basically recommend to avoid imports that have 'lib' in their paths.

The two following are the one you mention :

Which one should I choose?

Choose the rule you want ! It will not cause any performance issue, and no rule would reduce errors over the other. Just pick one and make your imports consistent across all your project, thanks to Dart linter.

I personnaly prefer using prefer_relative_imports, as it is recommended by Dart team, with this VSCode extension which automatically fix and sort my imports.

Heeled answered 13/2, 2021 at 18:30 Comment(4)
Good call, especially with VSCode extension, saves a lot of time.Liu
vscode-dart-import extension works fine. Thanks.Apulia
If you use build_runner then you should also definitely use relative imports (github.com/dart-lang/build/issues/3526#issuecomment-1576934849)Odiliaodille
One aspect that speaks for package imports is that if you move your file to another location in your folders you don' have to update the importsInundate
C
72

From the same Dart guidelines, further down they give this reason for the relative imports:

There is no profound reason to prefer the former—it’s just shorter, and we want to be consistent.

Personally, I prefer the absolute method, despite it being more verbose, as it means when I'm importing from different dart files (in other folders), I don't have to work out where the file to be imported is, relative to the current file. Made-up example:

I have two dart files, at different folder levels, that need to import themes/style.dart:

One is widgets/animation/box_anim.dart, where the relative path import would be:

import '../../themes/style.dart';

The other is screens/home_screen.dart with the relative import:

import '../themes/style.dart';

This can get confusing, so I find it better to just use the absolute in both files, keeping it consistent:

import 'package:myapp/themes/style.dart';

And just stick that rule throughout. So, basically, whatever method you use - Consistency is key!

The Linter for Dart package, also has something to say about this, but is more about the Don'ts of mixing in the '/lib' folder:

DO avoid relative imports for files in lib/.

When mixing relative and absolute imports it's possible to create confusion where the same member gets imported in two different ways. An easy way to avoid that is to ensure you have no relative imports that include lib/ in their paths.

Chadwickchae answered 5/5, 2020 at 2:47 Comment(0)
H
49

TLDR; Choose the one you prefer, note that prefer_relative_imports is recommended in official Effective Dart guide

First of all, as mentioned in this answer, Provider do not recommands package imports anymore.

Dart linter provides a list of rules, including some predefined rulesets :

Imports rules

There is actually more than two opposites rules concerning imports :

  • avoid_relative_lib_imports, enabled in pedantic and lints rulesets, basically recommend to avoid imports that have 'lib' in their paths.

The two following are the one you mention :

Which one should I choose?

Choose the rule you want ! It will not cause any performance issue, and no rule would reduce errors over the other. Just pick one and make your imports consistent across all your project, thanks to Dart linter.

I personnaly prefer using prefer_relative_imports, as it is recommended by Dart team, with this VSCode extension which automatically fix and sort my imports.

Heeled answered 13/2, 2021 at 18:30 Comment(4)
Good call, especially with VSCode extension, saves a lot of time.Liu
vscode-dart-import extension works fine. Thanks.Apulia
If you use build_runner then you should also definitely use relative imports (github.com/dart-lang/build/issues/3526#issuecomment-1576934849)Odiliaodille
One aspect that speaks for package imports is that if you move your file to another location in your folders you don' have to update the importsInundate
P
14

Provider do not need packages imports anymore.

This was a workaround to an old Dart bug: Flutter: Retrieving top-level state from child returns null

TL;DR, by mixing relative and absolute imports, sometimes Dart created a duplicate of the class definition.

This led to the absurd line that is:

import 'package:myApp/test.dart' as absolute;
import './test.dart' as relative;

void main() {
  print(relative.Test().runtimeType == absolute.Test().runtimeType); // false
}

Since provider relies on runtimeType to resolve objects, then this bug made provider unable to obtain an object in some situations.

Puberty answered 12/2, 2020 at 9:19 Comment(2)
You are writing in the past tense, is this bug solved now ?Heeled
But the question, when to use which way of importing, is still open. Is there a rule or best practice, when to do it one way and when the other?Poirier
E
11

My 5 cents on the topic are that absolute (package:my_app/etc/etc2...) imports cause much less trouble than relative ones (../../etc/etc2...) when you decide to reorganize/cleanup your project`s structure because whenever you move a file from one directory to another you change the "starting point" of every relative import that this file uses thus breaking all the relative imports inside the moved file...

I'd personally always prefer absolute to relative paths for this reason

Earthy answered 19/8, 2022 at 14:27 Comment(2)
I've seen the latter being true, refactoring especially in intellij gets screwed up with absolute imports, could as well be an IDE/tooling issue.Octaviooctavius
You can also do as I do which is using absolute imports with no package indication.Together
C
4

This question already has good answers, but I wanted to mention an insanely annoying and hard-to-find problem I experienced with unit testing that was caused by a relative import.

The expect fail indicator for an exception-catching expect block

expect(
  () => myFunction,
  throwsA(isA<InvalidUserDataException>())
);

was showing the actual result as exactly the same as the expected result, and zero indication of why it's failing.

After massive trial-and-error, the issue was because the expected InvalidUserDataException (a custom-made class) was being imported to the test file in RELATIVE format vs PACKAGE format.

To find this, I had to compare side-by-side, line-by-line, call-by-call between this test file and another test file that uses the exact same exception expecters (It's lucky, we had this), and just by chance, I happened to scroll to the top of this file's imports and see the blue underline saying prefer relative imports to /lib directory.

No, they're not preferred; they're necessary, because the moment I changed that to a PACKAGE (absolute) import, everything suddenly started working.

What I learned from this is: Use absolute imports for test files (files outside the lib directory)

  • e.g. inside of src/test/main_test.dart
    • DON'T: use import '../lib/main.dart'
    • DO: use package:my_flutter_app/main.dart

Maybe other people knew this already, but I didn't, and I couldn't find anything online with searches about this issue, so I thought I would share my experience that might help others who got stuck around this.

Does anyone know why this happens?

Edit: For context, this happened while using Flutter 2.1.4 (stable) with Sound Null Safety

Chromatics answered 20/5, 2022 at 5:34 Comment(3)
I don't know what caused your problem exactly, but your discovery is mentioned here, might be worth taking a look at these docs to avoid future trouble :). dart.dev/guides/language/effective-dart/usage Specifically the "DON’T allow an import path to reach into or out of lib." part: "(...) a relative import path in a file inside lib can’t reach out and access a file outside of the lib directory, and a library outside of lib can’t use a relative path to reach into the lib directory. Doing either leads to confusing errors and broken programs."Latini
@KasiaK. I looked at your reference and it does say not to do that, but also says nothing about why it happens, and doesn't seem to lint for it on my VS Code. Either way, thanks for the link.Chromatics
I do not see how this answers the question at the top of this page, but it should. Please edit according to How to Answer or delete the answer. Otherwise it risks being flagged as "not an answer" and being deleted.Harlotry
S
2

Do you use Integration Tests?

If the answer is yes, then in most cases you need to use package imports. When you attempt to run your integration tests on a physical device, any relative imports will not be able to find what they're looking for.

Example: https://github.com/fluttercommunity/get_it/issues/76

You can enforce package imports in your project by using these two linting rules:

I also prefer package imports because they stick even when rearranging your files and folders. Relative imports frequently break and it's a pain to have to remove them and reimport the offending dependency.

Scale answered 22/7, 2022 at 23:24 Comment(0)
V
0

I'd recommend using absolute imports if your project is subject to change.

if you want to reorganize your project by dividing it into modules, it will be much harder to do a search and replace on relative imports due to their nature "../../".

Volar answered 15/4, 2024 at 11:39 Comment(0)
D
-1

One very simple reason to not use package imports: rename your package without editing every dart file

Renaming can happen a few times while the product does not have a definitive name, and you or your product owner decides to change it.

It is much more painful to rename with package imports as your package name is in every import.

Of course you can change it with a find/replace query, but it's a useless edit on every dart file you can avoid with relative imports.

Plus, vscode allows to automatically update relative imports on file move/rename and I have never had any issue with this feature.

Diehl answered 2/2, 2023 at 9:57 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.