Using Jest-Dynamodb in Apple Silicon Platform Workaround

I have received a new 14″ Macbook Pro with M1 Pro CPU from work. I don’t experience any issue with macOS applications, most of the applications I use provided the Silicon version already. However, I faced some unit tests failing in NodeJS code repositories I am working on, while they can pass the tests in all other platforms – including the macOS Intel platform.

After digging into the error message, one of the reasons is related to the Jest-Dynamodb.

Dec 24, 2021 9:26:36 PM com.almworks.sqlite4java.Internal log
WARNING: [sqlite] cannot open DB[1]: com.almworks.sqlite4java.SQLiteException: [-91] cannot load library: java.lang.UnsatisfiedLinkError: /private/var/folders/q2/smpmq5gs1vlclkfn3s971b800000gp/T/dynamodb-local/DynamoDBLocal_lib/libsqlite4java-osx.dylib: dlopen(/private/var/folders/q2/smpmq5gs1vlclkfn3s971b800000gp/T/dynamodb-local/DynamoDBLocal_lib/libsqlite4java-osx.dylib, 0x0001): tried: '/private/var/folders/q2/smpmq5gs1vlclkfn3s971b800000gp/T/dynamodb-local/DynamoDBLocal_lib/libsqlite4java-osx.dylib' (fat file, but missing compatible architecture (have 'i386,x86_64', need 'arm64e')), '/usr/lib/libsqlite4java-osx.dylib' (no such file)
Dec 24, 2021 9:26:36 PM com.almworks.sqlite4java.Internal log
.....

The error message libsqlite4java-osx.dylib' (fat file, but missing compatible architecture (have 'i386,x86_64', need 'arm64e' indicated the issue – sqlite4java does not provide the arm64e architecture.

Jest-DynamoDB is built on top of the AWS DynamoDB-local which uses sqlite4java (https://bitbucket.org/almworks/sqlite4java/src/master/) – a repo is no longer maintained with last updated time on 26th May 2019, before Apple released the Silicon platform.

Replacing jest-dynamodb by jest-dynalite

Dynalite is a lightweight dynamodb local replacement. It provides a fast in-memory solution without overheads of Java / Docker dependence, but with limited functionality, e.g. Transaction is not yet supported. The latest release of Dynalite is 3.2.1 on 10th Sept 2020.

jest-dynalite is a drop-in replacement of the jest-dynamodb if your project is only used the feature supported by Dynalite. Update the jest.config.js preset attribute value from jest-dynamodb to jest-dynalite and renaming jest-dynamodb-config.js to jest-dynalite-config.js (rename the attribute in jest-dynalite-config.js from port to basePort and disable parallel run if you face any issues)

Installing macOS Intel X64 Java SDK

If you searched in Google, this is the solution you can find. You need to install the Rosetta 2 to allow macOS to simulate the Intel environment. You should not face any issue by this method, however, the Java SDK is not running natively.

Using the Java SDK package manager to switch Java SDK

If you want to run the application natively as much as possible, you can use the Java SDK package management software to switch the Java SDK version (and architect) for the jest-dynamoDB in theory.

SDKMAN!

SDKMAN! is a tool to manage parallel versions of multiple Java SDKs. However, as all of the candidates in the SDKMAN! are providing the Apple Silicon built (I tested it with toggling sdkman_rosetta2_compatbile flag), so unless the manual setup is involved, you cannot install the Intel version SDK. (I did not test the manual setup if jest-dynamodb can work correctly with SDKMAN!)

JEnv

JEnv is also allowed you to switch Java SDK version. It does not provide any installation of the Java SDK, so you need to install the Java SDK first and then set up the JEnv. JEnv uses the provider name and version to set up the alias name, so you cannot use the out-of-box feature to set up the Java SDK from the same provider with different architectures.

Based on my testing, jest-dynamoDB is working well with jenv shell (Shell Environment) and jenv global (Global environment), but not jenv local (Local / Project-based environment). I need to use jenv global for WebStorm to work correctly. (I tried to modify the project JAVA_HOME in the project testing environment, but it did not work). JEnv will be good if you are happy to switch the SDK version manually in the shell environment or change it globally (and set up your other projects back to use native SDK locally)

sqlite4java community build for macOS Apple Silicon

sqlite4java does not support the Apple Silicon platform also causes the issue for other software. sqlite4java built for Apple Silicon has been published in maven (https://search.maven.org/artifact/io.github.ganadist.sqlite4java/libsqlite4java-osx-arm64/1.0.392/dylib) by the community (https://issues.sonatype.org/browse/OSSRH-66040).

To apply this build, download the dylib package and replace libsqlite4java-osx.dylib located in your private folder. Please backup the original file. I have tested it in my project and no issue is with it. You may need to run xattr -d com.apple.quarantine libsqlite4java-osx.dylib for the macOS security warning.

However, as it is a community build, there may be no future maintenance and /private/var/folders is a temp folder that macOS will clear after each reboot, so dynamodb-local (npm package one) will try to reinstall again and you need to patch again.

Compersion of the workarounds

ProCon
jest-dynalite– Fast
– No dependency on JVM / Docker
– Not support all the dynamoDB feature
– Latest release is more than 1 year ago
Install x64 Intel Java SDK– Working as is– Java SDK is not running natively. Performance degraded
– All the other Java/projects are using the Intel Java SDK
Manage Java SDK with JEnv– Other software/projects can use the native Java SDK– Does not support jenv local, can be running with jenv shell or jenv global only
sqlite4java Community build for Apple Silicon– Run the dynaomdb-local natively– Manual operation is required after reboot
– Maybe no future maintenance
Summary of workaround

Future possible solutions

  1. AWS updates the dynamodb-local to support Apple Silicon
  2. Jest-dynamodb support dynamodb-local docker setup

A Polyglot Software Engineer and Technical Consultant who is interesting in technology, programming, sports and reading. He is living in Melbourne, Australia and original form Hong Kong.

6 Comments

  1. Hi Joseph,
    thanks for the helpful post.

    If you save libsqlite4java-osx.dylib under /usr/local/lib it will survive reboots and local-dynamodb will look for the library there as well.

    1. Hi Dalen. I have tried to save the file under /usr/local/lib, but the jest-dynamodb DB still reporting the error for the tmp folder (/private/var/folders)

      1. The error message I got, showed a list of folders where local-dynamodb looks for the dylib. One of them was /usr/local/lib. So, after I copied the dylib you linked in /usr/local/lib, it started working and it does work also after a restart 🙂

  2. Thanks for this post, it lead me to the right answer! (for my use case at least)

    TL;DR ended up using sdkman; see last paragraph

    Tried jest-dynalite, but ran into test issues as it looks like the credentials config values are not being used properly in this module. There are several open issues on jest-dynalite regarding this. I tried a few suggested fixes, but none worked so moved on.

    Tried community build of sqlite4java, and this works. However, as you mentioned every time your restart your computer you have to manually replace the sqlite4java lib with the arm64 version. I’m guessing you can probably write a script for this, but if the whole team is on M1s will be quite the annoyance.

    Finally tried SDKMAN, and this worked out perfectly. Even though it’s not running natively, for my case of just running tests it’s sufficient. It turns out that once you set the sdkman_rosetta2_compatbile flag in the sdkman config, install a x64 version of jdk, you can change the sdkman_rosetta2_compatbile flag back, and forever on that version will run the x64 installed version. So every time I want to run my tests I would just switch to the x64 version I installed, run the tests, and be done with it. Since sdkman only sets the version for the terminal session in which you switch java versions, your other terminal windows will still be on your default java version.

    SDKMAN Procedure

    install sdkman
    install a default java jdk for arm64 (sdk list java, pick a version, sdk install java )
    open .sdkman/etc/config in a text editor and update the flag “sdkman_rosetta2_compatible” to “true”
    install different java jdk version, NOT the same as the arm64 version, and do NOT set as default (sdk list java, pick a version, sdk install java )
    set “sdkman_rosetta2_compatible” back to “false” as to not affect future installs
    use the x64 jdk version you installed in step 4 (sdk use java )
    run your code that uses jest-dynamodb, and it should not have the error anymore

    Bonus: set a script in your bashrc, bash_profile, or w/e you use to quickly switch java version to your x64 version

    jdkx64() {
    sdk use java
    }

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.