# Importing TOML in React Native

This is a no bullshit quick note that I also can use in the future.

I love to use TOML in `i18next` because I also comment the translations to give them context. The problem is, there’s no standard way to simply import TOML files in a React Native project.

Metro is the bundler for React Native projects. In our case, it has a very useful feature: Transforming source codes.

Transforming is basically taking in a source code that is not native to JS (like TOML, YAML etc.), and converting it into native JS type. Of course, this is oversimplified.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1760292989939/16e1043f-0fe7-40e5-95bd-44635cb765ca.png align="center")

So, when you do `import enTranslation from “@/assets/translations/en.toml”`, Metro will parse TOML and convert it into native JS.

We also need a parser for TOML, and I think [smol-toml](https://www.npmjs.com/package/smol-toml) is the most maintained one at the time I am writing this.

So, let’s first create `metro.transformer.js` and add this code:

```javascript
// import transformer
const upstreamTransformer = require("@expo/metro-config/babel-transformer");
// import parser
const { parse } = require("smol-toml");

module.exports = {
  // export custom transform function
  transform: (config) => {
    // spread config, we need individual vars
    const { src, filename, options } = config;

    // if file is toml
    if (filename.endsWith(".toml")) {
      try {
        // parse it
        const parsedData = parse(src);
        // act like it's a JS module and export the data
        const code = `module.exports = ${JSON.stringify(parsedData, null, 2)};`;

        // transform the result
        return upstreamTransformer.transform({
          src: code,
          filename,
          options,
        });
      } catch (error) {
        // if there's error, do not compile
        throw new Error(
          `Error parsing TOML file ${filename}: ${error.message}`
        );
      }
    }

    // Use default transformer for other files
    return upstreamTransformer.transform(config);
  },
};
```

This is not where it ends, though. We also need to add it to `metro.config.js`.

```javascript
const { getDefaultConfig } = require("expo/metro-config");

// get default config
const config = getDefaultConfig(__dirname);

// introduce transformer into default config
config.transformer = {
  ...config.transformer,
  // define transformer path here
  babelTransformerPath: require.resolve("./metro.transformer.js"),
};

// introduce resolver, without this, import will not recognize toml imports
config.resolver = {
  ...config.resolver,
  sourceExts: [...config.resolver.sourceExts, "toml"],
};

module.exports = config;
```

After this, you can safely import TOML files:

```javascript
import enTranslations from "@/assets/translations/en.toml";
```

Of course, you will see some problems about Typescript being unable to define types. Create `toml.d.ts` at root of your project and define type:

```typescript
declare module "*.toml" {
  const value: Record<string, unknown>;
  export default value;
}
```

And add it to your `tsconfig.json`.

```json
{
  "extends": "expo/tsconfig.base",
  "compilerOptions": {
    "strict": true,
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": [
    "**/*.ts",
    "**/*.tsx",
    ".expo/types/**/*.ts",
    "expo-env.d.ts",
    "nativewind-env.d.ts",
    "toml.d.ts", // add type definition file here
  ]
}
```
