mlainez

mlainez

The journey to running Nerves on a Kobo Clara e-reader

For a few years now, I’ve been hesitant to buy an e-reader. I dislike that most of them have closed ecosystems. I was waiting for a “hacker-friendly” device and had high hopes for the PineNote. Unfortunately, the price tag of the PineNote and the difficulty of getting my hands on one left me without a “cheap” alternative. The PineNote is also much more than an e-reader and significantly larger, while I was looking for an open, pocket-sized device.

Kobo is a Toronto-based company that has released several e-reading devices over the past decade, and they have had a small, active hacker community building apps and plugins for their products. Initially, their devices shipped with an internal SD card you could replace with another operating system after opening the device, but later models now run their software on eMMC. Since they offered a cheap 6-inch entry model, the Clara (BW and Color), I decided to give it a try and ordered the Clara Color.

Kobo Clara Color

Ever since I started porting Buildroot and Nerves to exotic devices (running Nerves on Android e-waste), each time I get a consumer device in my hands, the first question that pops into my head is:

Will it run Nerves?

This topic is about answering that question and documenting my journey to understand how the device works and how to access relevant information so I can maybe build a Nerves firmware for it. I have no clue if I will make it, but documenting the process and progress might be interesting to some people here.

I’ll be adding posts to this topic, at random intervals, with my progress in the hope of helping demystify what it takes to get Nerves and Elixir running on consumer products and to inspire others to try to do the same.

Most Liked

mlainez

mlainez

Getting to know Clara

My first step is to figure out what information I can get from the device without opening it. The back cover shows that it’s a N367B model.

Since Kobo apparently has partnered with ifixit, I was able to find some guides showing the devices motherboards. There are two models the N367 and N367B.

We can clearly see a UART port on the top-left side of the N367 motherboard. A UART port is an asynchronous serial interface that uses separate TX (transmission) and RX (reception) lines for bidirectional communication.

On the right side of N367B motherboard, there seems to be something similar but without the same markings, so it would need some further investigation later on.

Why am I trying to figure out if there is a UART port somewhere? Because on most devices, this is where boot messages get printed. You can see what happens in the boot chain and, for linux based systems, the kernel messages, just like when your computer starts. This gives a lot of valuable information to create a bootable system later on. Some manufacturers use a UART port to flash the device before they leave the factory.

So, as finding a suitable UART port would require further investigation on my model and I didn’t want to open it up right away, I started trying to figure out if there was a way to stop the boot process and put the device in either fastboot mode or something else. Usually, you need to find a sequence of actions to perform when the device boots to get there.

Fastboot mode

I tried pressing the power button multiple seconds before pluging the usb cable, different combinations of pluging, unplugging, pressing the button etc… But it was not it.

Some devices sometimes require the host to “poll” the device with a fastboot command for them to interrupt their booting process. So,here’s how I managed to get it into fastboot.

  1. Turn off and unplug the Clara from your computer
  2. Launch the fastboot getvar all command on your computer
  3. Plug the Clara to your computer
  4. Quickly hold the power button until you see information in your host console
  5. Release the power button
  6. The Clara is now in fastboot mode

This is what you should get in your terminal:

➜  ~ fastboot getvar all
< waiting for any device >
(bootloader) 	hwcfg.PCB: [0] PCB=0x71
(bootloader) 	max-download-size: 0x1e00000
(bootloader) 	version: 0.5
all: Done!!
Finished. Total time: 0.003s

It doesn’t tell us much for now, but having the Clara in fastboot is useful if we want to flash existing partitions, or if we want to try a new boot image without flashing the emmc and potentially bricking it.

To get out of fastboot mode, just press the power button approximately 10 seconds.

Investigating the filesystem

When plugging the Clara to your computer, you can mount it as a mass storage device and put books on it. So let’s see what’s on that partition:

➜  KOBOeReader ls
fonts
➜  KOBOeReader ls -la
total 8364
drwxr-xr-x   7 marc marc    8192 jan  1  1970 .
drwxr-x---+  3 root root    4096 nov 15 12:13 ..
drwxr-xr-x   2 marc marc    8192 nov 14 10:19 .adobe-digital-editions
drwxr-xr-x   3 marc marc    8192 aoû 28 11:10 fonts
drwxr-xr-x  11 marc marc    8192 nov 15 12:13 .kobo
drwxr-xr-x  49 marc marc    8192 nov 14 11:36 .kobo-images
➜  KOBOeReader 

This kobo dot folder seems interesting, let’s check what’s in it:

➜  KOBOeReader ls -la .kobo
total 576
drwxr-xr-x 11 marc marc   8192 nov 15 12:13 .
drwxr-xr-x  7 marc marc   8192 jan  1  1970 ..
-rw-r--r--  1 marc marc     25 nov 14 10:19 affiliate.conf
drwxr-xr-x  2 marc marc   8192 nov 14 11:34 assets
drwxr-xr-x  2 marc marc   8192 nov 14 11:35 audiobook
-rw-r--r--  1 marc marc  19456 nov 15 12:06 BookReader.sqlite
drwxr-xr-x  2 marc marc   8192 nov 14 10:19 certificates
drwxr-xr-x  2 marc marc   8192 nov 14 11:34 custom-dict
-rw-r--r--  1 marc marc     75 nov 14 10:19 device.salt.conf
drwxr-xr-x  2 marc marc   8192 nov 14 11:35 dict
drwxr-xr-x  2 marc marc   8192 nov 14 11:36 dropbox
-rw-r--r--  1 marc marc   3072 nov 14 11:34 fonts.sqlite
drwxr-xr-x  2 marc marc   8192 nov 14 11:34 guide
drwxr-xr-x  2 marc marc   8192 nov 14 11:34 kepub
drwxr-xr-x  2 marc marc   8192 nov 14 10:19 Kobo
-rw-r--r--  1 marc marc 427008 nov 15 12:13 KoboReader.sqlite
-rw-r--r--  1 marc marc    105 nov 14 10:19 ssh-disabled
-rw-r--r--  1 marc marc     82 nov 15 12:12 version

Hang on… What is this ssh-disabled file…

To enable ssh:
- Rename this file to ssh-enabled
- Reboot the device
- Connect via: ssh root@<device_ip>

Ok, this is exciting :star_struck: Having ssh access as root would allow us to gather everything we need to run buildroot and Nerves on this thing.

SSH access

After renaming that file and ejecting the device, getting it’s IP from my dhcp server lease list, I was, as promised, able to connect to the Clara as root… :confetti_ball:

[root@kobo ~]# uname -a
Linux kobo 4.9.77 #1 SMP PREEMPT d226bc7bf-20250103T160218-B0103160930 armv7l GNU/Linux
[root@kobo ~]# cat /proc/cpuinfo 
processor	: 0
Processor	: ARMv7 Processor rev 4 (v7l)
model name	: ARMv7 Processor rev 4 (v7l)
BogoMIPS	: 15.60
Features	: half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm aes pmull sha1 sha2 crc32 
CPU implementer	: 0x41
CPU architecture: 7
CPU variant	: 0x0
CPU part	: 0xd03
CPU revision	: 4

Hardware	: MediaTek MT8110 board
Revision	: 0000
Serial		: 1234567890ABCDEF
[root@kobo ~]# ls -la /dev/disk/by-partlabel/
total 0
drwxr-xr-x    2 root     root           280 Nov 15 12:21 .
drwxr-xr-x    7 root     root           140 Nov 15 12:21 ..
lrwxrwxrwx    1 root     root            15 Nov 15 12:21 UBOOT -> ../../mmcblk0p2
lrwxrwxrwx    1 root     root            15 Nov 15 12:21 bl2 -> ../../mmcblk0p1
lrwxrwxrwx    1 root     root            15 Nov 15 12:21 boot_a -> ../../mmcblk0p4
lrwxrwxrwx    1 root     root            15 Nov 15 12:21 hwcfg -> ../../mmcblk0p6
lrwxrwxrwx    1 root     root            15 Nov 15 12:21 ntxfw -> ../../mmcblk0p7
lrwxrwxrwx    1 root     root            15 Nov 15 12:21 nvram -> ../../mmcblk0p3
lrwxrwxrwx    1 root     root            16 Nov 15 12:21 recovery -> ../../mmcblk0p11
lrwxrwxrwx    1 root     root            16 Nov 15 12:21 system_a -> ../../mmcblk0p10
lrwxrwxrwx    1 root     root            15 Nov 15 12:21 tee_a -> ../../mmcblk0p5
lrwxrwxrwx    1 root     root            16 Nov 15 12:21 userdata -> ../../mmcblk0p12
lrwxrwxrwx    1 root     root            15 Nov 15 12:21 vendor -> ../../mmcblk0p9
lrwxrwxrwx    1 root     root            15 Nov 15 12:21 waveform -> ../../mmcblk0p8
[root@kobo ~]# 

This tells us already quite a lot of things:

  • It’s running an old kernel, probably custom
  • It’s an Armv7 32 bits
  • It seems to rely on AB partitioning and has partitions dedicated to configuration, waveform information for the e-ink screen, etc…

I now need to understand a bit better how all of this is wired up, and also which drivers are used.

[root@kobo ~]# lsmod
wlan_drv_gen4m 1908365 0 - Live 0xbf14a000 (O)
wmt_cdev_bt 16871 0 - Live 0xbf141000 (O)
wmt_chrdev_wifi 12825 1 wlan_drv_gen4m, Live 0xbf138000 (O)
wmt_drv 1059215 4 wlan_drv_gen4m,wmt_cdev_bt,wmt_chrdev_wifi, Live 0xbf000000 (O)

lsmod doesn’t provide much info so I’m assuming there is a lot of stuff compiled within the kernel and some custom logic happening in the init proces. Time to dig into the filesystem and the different partitions! :nerd_face:

17
Post #2
mlainez

mlainez

From a working buildroot image to a booting Nerves System

From my past experience porting Nerves on devices, when you reach the point where you have a working buildroot system, you have made 70% of the work already, and what’s left is to make sure you get a few things ready:

  • Create your Nerves system project boilerplate, following the usual anatomy of a Nerves system
  • Create a nerves_defconfig with the proper Nerves specific options and linking relevant parts to the Nerves System BR external tree config files and scripts
  • Move all packages you needed for your buildroot system to your Nerves System project
  • Write the fwup configuration for your device
  • Make sure your fw_env.config fits your fwup configuration

Although most of this can be “standardized”, there is always something specific about the devices we try to run Nerves on, and it can make it more or less complicated to get to a fully functioning system. But usually, just to see a system boot (not supporting all the board’s features for instance), you don’t need much.

In this case though, we can call my setup a bit “unorthodox”. I’m trying to run Nerves from a loop device created from a binary file in one of the ereader’s partitions… Moreover, I can’t change the kernel, so I’m stuck with a 4.9 Android kernel, and a provided toochain using GCC 4.9. So I expect some compilation issues when using a recent buildroot…

Getting all required packages to compile

Standards matter

The first thing that I stumbled upon when compiling the system were errors like these:

error: 'for' loop initial declarations are only allowed in C99 or C11 mode
     for (size_t counter = 0; counter < length; counter++)
     ^
note: use option -std=c99, -std=gnu99, -std=c11 or -std=gnu11 to compile your code

This is due to the fact that our compiler supports the C89 open standard by default for C code, and in that standard, initial declaration in for loops need to be outside the for statement, like this:

size_t counter = 0;
for (counter; counter < length; counter++)

So you need to tell the compiler to use another standard. And the way to do that is to override the buildroot packages .mk files in our own nerves_system.

Although the solution was the same for several packages, it had to be done differently for some, since all packages makefiles are not exactly the same, may use different variables, etc…

An example of this can be found already in the buildroot system where I had to add eudev to add Wifi support.

Missing headers

Due to the fact the toolchain is using an old GCC 4.9 compiler, there are some features missing, and one of them was the lack of the getrandom function in sys/random.h.

This function is called by erlinit in the seedrng.c and it falls back to using /dev/randomin case of an issue (as far as I understood what it does). It means that I can just write a “stub” that will return -1 (fail) with a specific error type, and it should work.

static inline ssize_t getrandom(void *buf, size_t count, unsigned int flags)
{
    (void)buf; (void)count; (void)flags;
    errno = ENOSYS;
    return -1;
}

Missing constants in sysroot headers

When compiling Vintage_net, it seemed that some constants were missing, I don’t have much clue what these constants do, but they were apparently added in later kernels. I was glad to have Claude in my life for this one tbh, and he gave me a nice patch to add to my system, in the form of an af_compat.mk file.

define AF_COMPAT_APPEND_HEADERS
	for hdr in \
		$(STAGING_DIR)/usr/include/linux/socket.h \
		$(HOST_DIR)/arm-buildroot-linux-gnueabihf/sysroot/usr/include/linux/socket.h; do \
		if [ -f $$hdr ] && ! grep -q "AF_KCM" $$hdr; then \
			printf '%s\n' \
			'#ifndef AF_KCM' \
			'#define PF_KCM 41' \
			'#define AF_KCM PF_KCM' \
			'#endif' \
			'#ifndef AF_IB' \
			'#define PF_IB 27' \
			'#define AF_IB PF_IB' \
			'#define PF_MPLS 28' \
			'#define AF_MPLS PF_MPLS' \
			'#endif' >> $$hdr; \
			"#endif" >> $$hdr; \
		fi; \
	done
endef

Patching Cairo

Another one I wouldn’t have been capable of figuring out is with Cairo and the fact that compiling with GCC 4.9 with the compile flag -O3 generates invalid instructions. But it seems that changing thi globally was not working so Claude figured out that the issue came from a very specific file and proposed a patch for it, that I still don’t fully understand… I am also not sure why Cairo is in every nerves_defconfig out there.

--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -38,6 +38,10 @@
  *      Carl Worth <cworth@cworth.org>
  */

+#if defined(__GNUC__) && __GNUC__ == 4
+#pragma GCC optimize ("O0")
+#endif
+
 #define _DEFAULT_SOURCE /* for strdup() */
 #include "cairoint.h"

Getting erlang to compile

There were a few options that needed to be added to the C flags, such as --disable-year2038 which is a problem with systems that represent time as 32-bit signed integers.

Indeed, the maximum date you can represent using this is January 19, 2038. The solution is to move to 64-bit which we can’t do here… So we need to disable it to avoid compilation errors.

I also had to explicitely tell erlang where to find supporting libraries for the compilation with erl_xcomp_sysroot.

Creating the fwup configuration

Since we are not running in a traditional setup, we don’t have a boot partition. It means out image looks like this:

# +----------------------------+
# | MBR                        |
# +----------------------------+
# | Firmware configuration data|
# | (formatted as uboot env)   |
# +----------------------------+
# | p0*: Rootfs A (squashfs)   |
# +----------------------------+
# | p0*: Rootfs B (squashfs)   |
# +----------------------------+
# | p1: Application (f2fs)     |
# +----------------------------+

This simplifies our configuration, so after some cleanup and setting up the environment variables to point to the right loop devices and making changes to the config files in /etc, I was ready to go to the next step.

# In fwup_include/fwup-common.conf
define(NERVES_FW_DEVPATH, "/dev/loop0")
define(NERVES_FW_APPLICATION_PART0_DEVPATH, "/dev/loop0p2")
# In erlinit.config
-m /dev/loop0p2:/root:f2fs:nodev:

Changing the init script

My image is now a bit more complex than before, and I need the original Kobo system to be able to read a squashfs partition. Since there are some modifications I will need at boot, I will also need to use overlayfs to make sure I can boot.

    insmod /mnt/onboard/.buildroot/modules/4.9.77/kernel/fs/squashfs/squashfs.ko 
    insmod /mnt/onboard/.buildroot/modules/4.9.77/kernel/fs/f2fs/f2fs.ko

    losetup -Pf "$img" || return 1
    mount -o ro /dev/loop0p1 "$NEWROOT" || return 1

    # --- tmpfs copy for writable root ---
    mkdir -p "$MERGED"
    mount -t tmpfs tmpfs "$MERGED" || return 1
    cp -a "$NEWROOT/." "$MERGED/" || return 1

    # --- pivot root ---
    mkdir -p "$MERGED/.oldroot" "$MERGED/proc" "$MERGED/sys" "$MERGED/dev"
    cd "$MERGED" 2>/dev/null || return 1
    pivot_root . .oldroot >/dev/null 2>&1 || return 1
    cd / 2>/dev/null || :
    ...
    exec /sbin/init

The full scipt can be found here.

The first boot

It was now time to try it out… And after some tweaking in the init script, I finally saw this after manually doing a modprobe g_ether in my serial console and trying ssh nerves.local.

You’ll notice that a few things are not quite right. It seems some things are not read properly, and the application part is not mounted.

Whenever you see these “UNKNOWN”, and Valid (unknown) on the firmware line, this usually means that you didn’t configure your fw_env.config properly, or that the uboot_env part of your image is somehow corrupted, so you should double check that the partition offsets in your fwup-common.conf and your fw_env.config actually match. In my case, it was a misconfiguration.

Fixing the application partition mount issue was also rather easy, I didn’t use the right loop device in my erlinit.config

# In fw_env.config
/dev/loop0	0x2000		0x2000		0x200			16

I made sure the sizes were correct for the uboot_env variables, where Nerves stores information about the platform, architecture, serial, active partition, etc…

I also made a couple of changes to my erlinit.config to load the g_ether module before the Erlang VM starts and fix it with the correct loop device.

--pre-run-exec modprobe g_ether
-m /dev/loop0p2:/root:f2fs:nodev:

And after reuploading the image on that userdata partition, there I was, with a booting Nerves system :confetti_ball:

Next steps

I still have work to do in order to really use this device. The first step is to add Wifi support like I did in my buildroot system, as well as add all I need to be able to manipulate the eInk screen.

There is also a big limitation to my current setup. Using loop devices from files, you can’t rewrite the filesystem when the file is mounted, which means that the usual mix firmware upload doesn’t work and each time I want to update my firmware, I have to boot the ereader on the Kobo OS to mount it as a mass storage device and copy paste the full .img file generated with mix firmware.image. It’s cumbersome but it works.

Something I can try to fix this is resize the userdata partition on the device to free up space at the end of the eMMC. Then I can create an extra partition and flash a full disk image on it like I did on the fairphone 2 with kpartx. But that’s for later.

My current todo list is:

  • Add Wifi initialization
  • Allow the use of the eInk screen in pure Elixir

That’s a fun way to start 2026… :nerd_face:

12
Post #8
mlainez

mlainez

Getting to a working buildroot system

Nerves can be seen as a “layer” on top of a Buildroot system. Buildroot is a build system that let’s you create a Linux root filesystem from scratch. It can also build the kernel and bootloader for you and packages it all in a nice image you can flash on an SD Card.

In order to have a working Linux device, you need at least three things:

  • A bootloader: a piece of code that initializes minimal hardware support to be able to launch a kernel. There can be different levels of bootloaders but let’s stick to this definition for this post
  • A kernel: the “code” that is being run first and manages processes, devices initialisation, memory management, …
  • A root filesystem: directories and files containing the programs you want to use, the libraries they depend on, some OS initialisation scripts, user management, your custom programs, …

The root filesystem is also refered to as the “userspace”.

On our Kobo, we already have a bootloader and a kernel that we cannot change (because of Secure Boot), so the only thing we need is a root filesystem that the kernel will mount to run its init script.

We also need a way to avoid booting on the Kobo OS and boot our own system instead. And we want to do that as soon as we can.

What happens at boot

Once the kernel kicks in, it mounts the partition that has the rootfs, usually passed as root= in the kernel command line, and will try to run /init or /sbin/init from it. It will run this script as PID1, meaning as the first process.

On our device, the cmdline has root=/dev/mmcblk0p10which means the kernel will mount /dev/mmcblk0p10 as / and run /sbin/init.

We need to replace this /sbin/init by something else, so that it will allow us to “switch” to our alternative root filesystem and execute that system’s /sbin/init instead.

This is actually what happens in a Nerves system. Instead or running the buildroot system’s /sbin/init, Nerves subsitutes it with erlinit, which gets ran as PID1.

Replacing Kobo’s /sbin/init

We need our replacement init script to do several basic things:

  • Mount all directories we need to be able to pivot to another system
  • Wait for an event to decide if we boot the alternate system
  • Mount our alternative system from and image somewhere on the userdata partition
  • Pivot to this system and run it’s /sbin/init as PID1

I’ve written this init script to do exactly that.

Here’s an extract of it, showing the most relevant parts. If a touch is detected on the screen during boot, we first try to mount our image file containing the alternative rootfs, then we use pivot_root to use that system’s root as / and have the old root mounted in .oldroot. We then move all the relevant mounts to the new system, unmount the old root and then execute the alternative rootfs /sbin/init as PID1.

mount -t ext4 -o loop,rw "$img" "$NEWROOT" >/dev/null 2>&1 || :
  mountpoint -q "$NEWROOT" 2>/dev/null || \
    mount -t ext4 -o loop,ro "$img" "$NEWROOT" >/dev/null 2>&1 || return 1

  [ -x "$NEWROOT/sbin/init" ] || return 1

  mkdir -p "$NEWROOT/.oldroot" "$NEWROOT/proc" "$NEWROOT/sys" "$NEWROOT/dev" >/dev/null 2>&1 || return 1
  cd "$NEWROOT" 2>/dev/null || return 1
  pivot_root . .oldroot >/dev/null 2>&1 || return 1

  cd / 2>/dev/null || :
  mount --move /.oldroot/dev /dev 2>/dev/null || :
  mount --move /.oldroot/proc /proc 2>/dev/null || :
  mount --move /.oldroot/sys /sys 2>/dev/null || :
  umount -l /.oldroot 2>/dev/null || :
  exec /sbin/init

Building an alternative rootfs

Now, we just need an image to boot from… You can find the buildroot external tree I used here.

The first step is to get to a system that compiles… And this is not always a walk in the park. Some of the issues along the way were due to the provided toolchain, kernel source, and Mediatek specific quirks.

1. Getting the kernel to compile (in order to have new modules in the rootfs)

The kernel is released as a .tar.zst-part-aa and .tar.zst-part-ab which is not really what buildroot expects. Moreover, inside this archive, there is also the Wifi driver source. So in order for buildroot to be able to use this, some gymnastics is needed in a Makefile extension.

2. Getting the Wifi drivers to compile

Next to that, still in the same makefile extension, I’ve added a LINUX_POST_BUILD_HOOKS += LINUX_BUILD_CONNECTIVITY_CMDS as a kernel post build hook to compile the Wifi drivers. but due to some require path issues, I had to create a patch to the wifi driver makefile

3. Building an image

Since I’m not going to have much in my image, only the rootfs, I don’t need a partition table, so Buildroot will just generate a blob with an ext4 rootfs in it that I can directly mount as a loop device.

image buildroot-kobo.img {
	hdimage {
		partition-table-type="none"
	}

	partition rootfs {
		image = "rootfs.ext4"
	}
}

Running the image for the first time

I created an init script to start usb networking when my system is initialized, it helps debugging in an easy way without the quirky jumper wires when using UART.

The buildroot image needs to be placed in .buildroot/buildroot-kobo.img on the userdata partition, so I just need to start the Kobo in it’s original OS, make it act as a mass storage device, and simply copy paste my image in the right folder.

I have also created to init scripts to support the E-ink screen that I won’t detail here but after booting (and obviously many trials and errors that wouldn’t fit this article’s narrative), here’s what we have :star_struck:

Probably not the most impressive image you’ve ever seen but this is quite a win :confetti_ball:

We can connect to it with usb and see that indeed, we are now running buildroot.

# cat /etc/os-release 
NAME=Buildroot
VERSION=2025.05.3-1-g85c588cdf9
ID=buildroot
VERSION_ID=2025.05.3
PRETTY_NAME="Buildroot 2025.05.3"
# 

Now do Nerves!

The first step to porting Nerves on anything is to first have a working Buildroot system. Now that it’s done, I can move to the next step and try running Nerves on it. I hope I can find workarounds to any future roadblocks ahead of this. But so far so good. I’m running the latest buildroot, on a 4.9 Android kernel full of Mediatek patches so I’m sure I will have to figure some more stuff out.

Will the next picture show a working Nerves system?

Where Next?

Popular in Discussions Top

matthias_toepp
I’d love to hear what people think about Wisp, the new Gleam web framework started by Gleam’s primary creator Louis Pilfold. Gleam, alon...
New
marciol
Please, let me know if this kind of discussion already took place in another topic . Hi all, how do you consider if is better to build ...
New
mikl
I wanted to capitalize a string, and tried using String.capitalize(). That generally works well, until you try to capitalize a word like...
New
thojanssens1
It would be nice to be able to define a redirect from one route to another from the router.ex file. E.g.: redirect "/", UserController, ...
New
jer
I’ve been using umbrellas for a while, and generally started off (on greenfield projects at least) by isolating subapps based on clearly ...
New
PragTob
Hey everyone, this has been on my mind for some time and I’d love your input on it! TLDR: I feel like maps are superioer for storing and...
New
und0ck3d
Hello everyone! A few days ago I’ve created a topic here about how people were creating CMSs with Elixir and Phoenix. I’ve been studying...
New
AstonJ
Can you believe the first professionally published Elixir book was published just 8 years ago? Since then I think we’ve seen more books f...
New
Fl4m3Ph03n1x
Background A few days ago I was listening to The future of Elixir from Elixir Talks, with Dave Thomas (@pragdave ) and Brian Mitchell. I...
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

Other popular topics Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 39523 209
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

We're in Beta

About us Mission Statement