As a seasoned software engineer working extensively with Flutter and Dart, I often come across questions like:

"When should I use part vs import? What’s the difference between export and import? Is there a clean way to split Dart files while maintaining readability and scalability?"

These questions usually come from developers looking to create well-structured, maintainable codebases. In this post, we’ll deeply explore Dart’s import, export, part, and part of directives — not just what they are, but when, why, and how to use them in real-world Flutter and Dart projects.

1. import: Bringing Code In

What It Does

The import directive is used to include external Dart libraries into your current file so you can use classes, functions, constants, etc., defined elsewhere.

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

Key Points

  • Supports both package and relative paths.

  • Prevents name clashes via as, show, or hide:

import 'utils.dart' as utils;
import 'math.dart' show add;
import 'math.dart' hide subtract;

When to Use

  • Always prefer import when including a reusable, standalone file.

  • Use as for namespaces in large codebases.

2. export: Sharing Code Out

What It Does

The export directive allows you to re-expose public APIs from one file in another — effectively acting as a public interface.

export 'src/models.dart';
export 'src/utils.dart';

Real-World Example

In a package:

// library.dart
export 'src/button.dart';
export 'src/input.dart';

Now, instead of:

import 'src/button.dart';
import 'src/input.dart';

You just do:

import 'library.dart';

When to Use

  • Building packages or public libraries.

  • Creating a clean API surface.

3. part: Breaking a File Into Pieces

What It Does

part is used to split a single Dart library (file) into multiple parts, all of which share the same scope and namespace.

// main.dart
library my_library;
part 'file_a.dart';
part 'file_b.dart';

In file_a.dart:

part of my_library;

Key Points

  • All part files must declare part of <library_name>;

  • Code is treated as if written in the main file — same scope.

  • Useful for splitting large files into smaller chunks.

When to Use

  • For logically grouped files that are not reusable independently.

  • Good for code generators (e.g., freezed, json_serializable).

  • Avoid in modular/shared code; prefer import for those cases.

4. part of: Declaring a Sub-File

What It Does

part of is used in a file that is a subcomponent of a main Dart library file.

part of my_library;

This tells Dart that this file doesn’t stand on its own — it’s part of another file.

Rules

  • Cannot use import or export in a part of file.

  • Cannot run independently.

Choosing Between import and part

Use Case

Recommended Directive

Independent utility or module

import

Code-gen driven file grouping

part/part of

Re-exporting API layers

export

If you want modular, testable, and scalable architecture — prefer import.
Use part only when files must share scope tightly (e.g., annotated models and their generated code).

Best Practices & Real-World Advice

  • Use export to simplify imports in consumer code.

  • Use part/part of only when it’s required (e.g., code generation).

  • Don’t use part to avoid writing import — it creates tight coupling.

  • Keep a consistent folder structure (e.g., lib/src/, lib/ui/, lib/models/).

  • Use a library.dart to aggregate and re-export key modules.

Final Thoughts

Understanding these four keywords is crucial to architecting clean, scalable Dart and Flutter projects. While import and export are your main tools for modularity and reuse, part and part of are valuable in niche cases like code generation and large file organization.

Write code as if you’re creating a public package — even for yourself.

That mindset will guide you toward using these tools wisely.

Happy coding!

Keep reading